<?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>Copter Labs</title>
	<atom:link href="http://www.copterlabs.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.copterlabs.com</link>
	<description>Smart Design for Smart People</description>
	<lastBuildDate>Fri, 08 Feb 2013 21:19:49 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Strict vs. Loose Comparisons in PHP</title>
		<link>http://www.copterlabs.com/blog/strict-vs-loose-comparisons-in-php/</link>
		<comments>http://www.copterlabs.com/blog/strict-vs-loose-comparisons-in-php/#comments</comments>
		<pubDate>Sun, 06 Feb 2011 22:48:57 +0000</pubDate>
		<dc:creator>Jason Lengstorf</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.copterlabs.com/blog/strict-vs-loose-comparisons-in-php</guid>
		<description><![CDATA[<p>Understanding how PHP&#8217;s comparison operators work can save you a lot of headache, and hopefully helps you prevent some strange bugs in your projects. <a href="http://www.copterlabs.com/blog/strict-vs-loose-comparisons-in-php/" class="more-link">More</a></p><p>The post <a href="http://www.copterlabs.com/blog/strict-vs-loose-comparisons-in-php/">Strict vs. Loose Comparisons in PHP</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<p>If you&#8217;ve come up against this in the past, this is going to sound like a     no-brainer, but for programmers who have only used PHP and don&#8217;t know the     difference between loose comparisons and the strict variety, this tip     might save a lot of headache.</p>
<h3>What&#8217;s the Problem?</h3>
<p>In what was an effort to make PHP more accessible to programmers,     variables in PHP can&#8217;t be declared with a specific      <a href="http://www.php.net/manual/en/language.types.php">type</a>. While     this <em>does</em> make it easier to get started, it also leaves room for     some confusing situations.</p>
<h4>Unexpected Output in Mathematical Operations</h4>
<p>The lack of a specific type means that PHP operates on a &#8220;best-guess&#8221;     principle (they call it     <a href="http://www.php.net/manual/en/language.types.type-juggling.php">type     juggling</a>), where <strong>PHP converts the value of a variable to the most     appropriate type for the action being carried out.</strong></p>
<p>This means that while you&#8217;ll usually get the expected results, there are     some cases where you can end up with some seemingly bizarre output.</p>
<p>For example, check out this code:</p>
<pre class="brush: php">echo 'fortieth' + 7; // Outputs 7
echo '40th' + 7; // Outputs 47</pre>
<p>Seems weird, right? What&#8217;s happening is that if a string starts with a     number, PHP will pull it out and use it as the value for mathematical     operations. Otherwise, it becomes 0.</p>
<h4>Unexpected Output from Loose Comparisons</h4>
<p><strong>A loose comparison is one performed using two equals signs (<code>==</code>).</strong> It follows suit with the &#8220;best-guess&#8221; approach, which can lead to some     unexpected results.</p>
<p>As proof, here are three different data types:</p>
<pre class="brush: php">echo gettype(0); // Outputs "integer"
echo gettype(FALSE); // Outputs "boolean"
echo gettype('test'); // Outputs "string"</pre>
<p>Now check out what happens when we compare these types of data:</p>
<pre class="brush: php">var_dump(0==FALSE); // bool(true)
var_dump(0=='test'); // bool(true)
var_dump(FALSE=='test'); // bool(false)</pre>
<p>This is confusing on several levels.</p>
<p>It does make sense that <code>0</code> and <code>FALSE</code> would be     considered equal. So we&#8217;re good so far, but the number <code>0</code> and the word &#8220;test&#8221;, in     pretty much every situation I can think of, should probably come back     <code>FALSE</code>. This one&#8217;s pretty odd to have come back <code>TRUE</code>,     but it goes back to the fact that PHP will try and convert &#8220;test&#8221; to an     integer, so it becomes <code>0</code> for the comparison.</p>
<p>Next, we&#8217;ve got <code>FALSE</code> and &#8220;test&#8221; coming back <code>FALSE</code>.     Well, that seems inconsistent. If &#8220;test&#8221; becomes <code>0</code>, and     <code>0==FALSE</code>, why doesn&#8217;t this one come out <code>TRUE</code> as     well?</p>
<p><em>(It&#8217;s happening because <code>FALSE=='test'</code> would require &#8220;test&#8221;     to undergo two type changes: string to integer <code>0</code>, then integer     to boolean. I think. Not the point. It&#8217;s just not intuitive.)</em></p>
<p>In most cases, loose comparisons aren&#8217;t a problem. But as we&#8217;ve seen, <strong>there     are a few cases where loose comparisons can cause really confusing bugs.</strong></p>
<p><em><strong>Extra Credit:</strong> Read the PHP manual entry on     <a href="http://www.php.net/manual/en/types.comparisons.php">type     comparisons</a>.</em></p>
<h4>I Don&#8217;t See How This Affects Me</h4>
<p>The above examples are pretty unlikely to appear in production code, so it     might be easy to write this off as a &#8220;Geek on a Soapbox&#8221; type post. That&#8217;s     not the case, though.</p>
<p><strong>Let&#8217;s look at an example that you might actually see in a real project.</strong> In     this snippet, the comments for an entry are counted and returned from the     database as an integer. If the query fails, boolean <code>FALSE</code> is     returned instead.</p>
<p><em>To make this example easy to reproduce, we&#8217;re going to replace the database     query with an explicitly set variable.</em> Let&#8217;s start by returning a count of     <code>5</code>.</p>
<pre class="brush: php">&lt;?php

echo "&lt;pre&gt;";

$comment_count = get_comment_count();

if( $comment_count==FALSE )
{
    echo "The entry count database query failed.";
}
else
{
    echo "The entry count is $comment_count.";
}

echo "&lt;/pre&gt;";

function get_comment_count(  )
{
    /*
     * This is a DB query; it returns an integer (number of comments) or
     * boolean FALSE on query failure. To keep this example concise, we're going
     * to fake the return value
     */
    $comment_count = 5;

    // Output the type of the comment count
    echo 'Database return value: ';
    var_dump($comment_count);

    // If our "DB query" fails, return FALSE to indicate failure
    if( $comment_count==FALSE )
    {
        return FALSE;
    }

    return $comment_count;
}

?&gt;</pre>
<p>The output is what we&#8217;d expect:</p>
<pre class="brush: js">Database return value: int(5)
The entry count is 5.</pre>
<p>And if we change line 25 to read <code>$comment_count = FALSE;</code> (which     means the query failed), we also see the expected output:</p>
<pre class="brush: js">Database return value: bool(false)
The entry count database query failed.</pre>
<p>However, what happens when an entry is new and doesn&#8217;t have any comments     yet? Check out the results when you change line 25 to <code>$comment_count =     0;</code> in the test code:</p>
<pre class="brush: js">Database return value: int(0)
The entry count database query failed.</pre>
<p>Uh oh. A valid integer, <code>0</code>, was returned, but <strong>our script     misinterpreted it as a failed database query!</strong></p>
<h3>Keeping It Clear and Logical &mdash; Enter Strict Comparisons</h3>
<p>Here&#8217;s where we can take one easy step to ensure that our code avoids as     many weird bugs as possible: <strong>switch to strict comparisons</strong>.</p>
<p><strong>A strict comparison is done with three equals signs (<code>===</code>)</strong>, and     it requires the two pieces of data being compared to have not only the same     value, but the same type as well.</p>
<p>Personally, I think <strong>you should use strict comparisons whenever possible.</strong></p>
<p>If we apply strict comparisons to our comment count example, we can see     that the bug goes away:</p>
<pre class="brush: php">&lt;?php

echo "&lt;pre&gt;";

$comment_count = get_comment_count();

if( $comment_count===FALSE )
{
    echo "The entry count database query failed.";
}
else
{
    echo "The entry count is $comment_count.";
}

echo "&lt;/pre&gt;";

function get_comment_count(  )
{
    /*
     * This is a DB query; it returns an integer (number of comments) or
     * boolean FALSE on query failure. To keep this example concise, we're going
     * to fake the return value
     */
    $comment_count = 0;

    // Output the type of the comment count
    echo 'Database return value: ';
    var_dump($comment_count);

    // If our "DB query" fails, return FALSE to indicate failure
    if( $comment_count===FALSE )
    {
        return FALSE;
    }

    return $comment_count;
}

?&gt;</pre>
<p>The output now comes out properly.</p>
<pre class="brush: js">Database return value: int(0)
The entry count is 0.</pre>
<h3>A Small Adjustment for a Lot Less Headache</h3>
<p><strong>It doesn&#8217;t take much to use strict comparisons in your code.</strong> And I can     promise you that you&#8217;ll barely notice the adjustment.</p>
<p><strong>You will, however, avoid one of those ghost-in-the-machine type bugs that     keeps you banging your head against the keyboard for an hour or two.</strong> (Trust     me. I know from experience.)</p>
<p><em><strong>NOTE:</strong> For a table detailing how comparisons work in     both loose and strict comparisons,     <a href="http://www.php.net/manual/en/types.comparisons.php">see the PHP     manual</a>.</em></p>
<h3>On an Unrelated Note</h3>
<p>For anyone who missed it, <strong>I had a couple articles run on Nettuts+     recently.</strong> If you haven&#8217;t already, check them out and read through them:</p>
<ul>
<li> <a href="http://net.tutsplus.com/tutorials/php/20-ways-to-save-kittens-and-learn-php/">20         Ways to Save Kittens and Learn PHP</a> </li>
<li> <a href="http://net.tutsplus.com/tutorials/php/simplify-form-handling-in-a-big-way/">Simplify         Form Handling in a Big Way</a> </li>
</ul>
<p>And, as always, I want to hear your thoughts, love, hate, and haiku in the     comments!</p>
<p>The post <a href="http://www.copterlabs.com/blog/strict-vs-loose-comparisons-in-php/">Strict vs. Loose Comparisons in PHP</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.copterlabs.com/blog/strict-vs-loose-comparisons-in-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Creating an App from Scratch: Part 9</title>
		<link>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-9/</link>
		<comments>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-9/#comments</comments>
		<pubDate>Mon, 14 Dec 2009 07:10:23 +0000</pubDate>
		<dc:creator>Jason Lengstorf</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-9</guid>
		<description><![CDATA[<p>Part 9 of the Creating an App from Scratch series, in which Chris Coyier and Jason Lengstorf go over bug fixes, security concerns, and other feature tweaks that occurred after the application went live. <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-9/" class="more-link">More</a></p><p>The post <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-9/">Creating an App from Scratch: Part 9</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<div id="series-header"><img src="/assets/images/app-from-scratch/09-header.jpg" alt="Creating a Web App from Scratch Part 9" /></div>
<div id="series-navigation">
<h5>All Series Navigation</h5>
<ul>
<li><a href="http://css-tricks.com/app-from-scratch-1-design">Part 1 &ndash; Planning the App: Basic Idea and Design</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-2/">Part 2 &ndash; Planning the App: Database Architecture and Development Approach</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-3/">Part 3 &ndash; Designing the App: Workflow Map and Photoshop Design</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-4-html-css">Part 4 &ndash; Designing the App: HTML and CSS</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-5/">Part 5 &ndash; Developing the App: User Interaction</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-6-ajax">Part 6 &ndash; Developing the App: Adding AJAX Interactivity</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-7/">Part 7 &ndash; Developing the App: List Interaction</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-8-finishing/">Part 8 &ndash; Wrapping Up</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-9/">Part 9 &ndash; Bugs, Security, and Other Tweaks</a></li>
</ul>
</div>
<h3>Bugs, Security, and Other Tweaks</h3>
<p>There were supposed to be only eight parts to this series, but as we started  releasing them, Chris and I realized that there was going to need to be a  follow-up post to address some of the bug fixes, security patches, and a few  other minor changes.</p>
<p><strong><em>NOTE: All the changes we&#8217;re going to cover in this article are  already included in  <a href="http://css-tricks.com/examples/WebAppFromScratch/">the source  code</a>.</em></strong></p>
<h3>Bug Fixes</h3>
<p>After releasing the live app, a handful of bugs showed up in the comments. We  tried to address these as quickly as possible to keep the app from causing  unnecessary grief for our users. We&#8217;ll go over the major bugs here.</p>
<h4>Account Created, List Failed Error</h4>
<p>The first thing we saw was that when there were more than just one or two  people trying to create accounts, <strong>the app started failing to create user lists  after an account was created.</strong> Upon reviewing the code, I found that the error  seemed to be coming from the following line:</p>
<pre class="brush: php">$userID = $this-&gt;_db-&gt;lastInsertId();</pre>
<p><tt>$userID</tt> seemed to be unreliable, and therefore the query to insert a  new list into the database was failing regularly. To fix this, we implemented  a complex query that worked around the use of <tt>lastInsertId()</tt>:</p>
<pre class="brush: php">            /*
             * If the UserID was successfully
             * retrieved, create a default list.
             */
            $sql = "INSERT INTO lists (UserID, ListURL) VALUES
                    (
                        (
                            SELECT UserID
                            FROM users
                            WHERE Username=:email
                        ),
                        (
                            SELECT MD5(UserID)
                            FROM users
                            WHERE Username=:email
                        )
                    )";</pre>
<p>Performance-wise, this is going to be slower than the original post, but it&#8217;s  incredibly more reliable (since implementing this fix, we&#8217;ve had no reports of  this error). <strong>Any MySQL supergeeks who may have a better solution, please post  it in the comments! </strong></p>
<h4>Double-Clicking &#8220;Add&#8221; Sometimes Added Duplicate Entries</h4>
<p>One little user interface quirk that was discovered was that you could click  multiple times in succession on the &#8220;Add&#8221; button. In our original JavaScript,  we only cleared the value of the input field upon a successful AJAX result.  That is ideal, since when that text disappears that is your visual queue that  it&#8217;s been added to your list successfully. Plus, generally that happens  quickly enough it feels pretty instant. However, if you straight up  &#8220;double-click&#8221; on that add button (which people absolutely still do that),<strong> you  might get two or more requests off before the success comes back and clears  the fields</strong> (when the field is clear, the submit button will do nothing).</p>
<p>One method to fix this could have been to clear the field as soon as a click  happens, but the problem there is that if the save is unsuccessful you&#8217;ll lose  your text. Instead, we just add a little more smarts. <strong>When the submit button  is clicked and there is text ready to add, the AJAX request is made and the  button is disabled. Upon success, the field is cleared and the button is  re-enabled.</strong> This ensures only one submission is possible.</p>
<p>In <tt>/js/lists.js</tt>, we added the following at line 114:</p>
<pre class="brush: js">    $('#add-new').submit(function(){

       //  ... variables and whitelist stuff ...

        if (newListItemText.length &gt; 0) {
            // Button is DISABLED
            $("#add-new-submit").attr("disabled", true);

            $.ajax({

                // Ajax params stuff

                success: function(theResponse){

                    // list adding stuff

                    // field is cleared and button is RE-ENABLED
                    $("#new-list-item-text").val("");
                    $("#add-new-submit").removeAttr("disabled");
     }</pre>
<p><strong><em>NOTE: As you can see, we remove the &#8220;disabled&#8221; attribute entirely  upon a successful response from our query. That is the only way to re-able a  submit button. Setting disabled to &#8220;false&#8221; has no effect.</em></strong></p>
<h4>Changing Email Address with a Blank Email Crippled Account</h4>
<p>It was also brought to our attention that <strong>clicking the &#8220;Change Email&#8221; button  with a blank field would not only succeed, but would cripple the account and  make it unusable.</strong> Fixing this was as simple as making sure the email address  submitted was valid by inserting the following in the <tt>updateEmail()</tt> method in  <tt>/inc/class.users.inc.php</tt>:</p>
<pre class="brush: php">        if( FALSE === $username = $this-&gt;validateUsername($_POST['username']) )
        {
            return FALSE;
        }</pre>
<p>Then, instead of binding the <tt>$_POST</tt> value to the query, we bind the  new variable <tt>$username</tt>, which contains the valid email address if the  check didn&#8217;t fail. Note the use of the new function  <tt>validateUserEmail()</tt>&mdash;we&#8217;ll go over that in the next section on  security.</p>
<h3>Security Issues</h3>
<p>After we worked the bugs out of our app, we turned to the security holes that  were pointed out by commenters. Some of these were simple oversights on our  part, and some of the problems were news to us. With the help of our readers,  though, we tried to patch everything up.</p>
<h4>JavaScript Could Be Inserted Into Edited Items</h4>
<p>When creating new items, we checked for any JavaScript in the input using the  <tt>cleanHREF()</tt> function, then stripped out unwanted tags on the server  side using <tt>strip_tags()</tt> and a whitelist of acceptable tags. However,  we had missed that JavaScript could be inserted into existing items when they  were edited. To correct this issue, we turned to a  <a href="http://api.kohanaphp.com/_input_8php-source.html">preexisting input  sanitizing function</a> (lines 00326-00384)  <a href="http://css-tricks.com/app-from-scratch-8-finishing/#comment-65438">posted  by Zoran</a> in the comments of  <a href="http://css-tricks.com/app-from-scratch-8-finishing/">Part 8</a>.</p>
<p>We wrapped the code in a method called <tt>cleanInput()</tt> and placed it  in <tt>/inc/class.users.inc.php</tt>:</p>
<pre class="brush: php">    /**
     * Removes dangerous code from the href attribute of a submitted link
     *
     * @param string $input        The string to be cleansed
     * @return string            The clean string
     */
    private function cleanInput($data)
    {
        // http://svn.bitflux.ch/repos/public/popoon/trunk/classes/externalinput.php
        //  ----------------------------------------------------------------------
        // | Copyright (c) 2001-2006 Bitflux GmbH                                 |
        //  ----------------------------------------------------------------------
        // | Licensed under the Apache License, Version 2.0 (the "License");      |
        // | you may not use this file except in compliance with the License.     |
        // | You may obtain a copy of the License at                              |
        // | http://www.apache.org/licenses/LICENSE-2.0                           |
        // | Unless required by applicable law or agreed to in writing, software  |
        // | distributed under the License is distributed on an "AS IS" BASIS,    |
        // | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or      |
        // | implied. See the License for the specific language governing         |
        // | permissions and limitations under the License.                       |
        //  ----------------------------------------------------------------------
        // | Author: Christian Stocker &lt;chregu@bitflux.ch&gt;                        |
        //  ----------------------------------------------------------------------
        //
        // Kohana Modifications:
        // * Changed double quotes to single quotes, changed indenting and spacing
        // * Removed magic_quotes stuff
        // * Increased regex readability:
        //   * Used delimeters that aren't found in the pattern
        //   * Removed all unneeded escapes
        //   * Deleted U modifiers and swapped greediness where needed
        // * Increased regex speed:
        //   * Made capturing parentheses non-capturing where possible
        //   * Removed parentheses where possible
        //   * Split up alternation alternatives
        //   * Made some quantifiers possessive

        // Fix &amp;entityn;
        $data = str_replace(array('&amp;amp;','&amp;lt;','&amp;gt;'), array('&amp;amp;amp;','&amp;amp;lt;','&amp;amp;gt;'), $data);
        $data = preg_replace('/(&amp;#*w )[x00-x20] ;/u', '$1;', $data);
        $data = preg_replace('/(&amp;#x*[0-9A-F] );*/iu', '$1;', $data);
        $data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');

        // Remove any attribute starting with "on" or xmlns
        $data = preg_replace('#(&lt;[^&gt;] ?[x00-x20"'])(?:on|xmlns)[^&gt;]* &gt;#iu', '$1&gt;', $data);

        // Remove javascript: and vbscript: protocols
        $data = preg_replace('#([a-z]*)[x00-x20]*=[x00-x20]*([`'"]*)[x00-x20]*j[x00-x20]*a[x00-x20]*v[x00-x20]*a[x00-x20]*s[x00-x20]*c[x00-x20]*r[x00-x20]*i[x00-x20]*p[x00-x20]*t[x00-x20]*:#iu', '$1=$2nojavascript...', $data);
        $data = preg_replace('#([a-z]*)[x00-x20]*=(['"]*)[x00-x20]*v[x00-x20]*b[x00-x20]*s[x00-x20]*c[x00-x20]*r[x00-x20]*i[x00-x20]*p[x00-x20]*t[x00-x20]*:#iu', '$1=$2novbscript...', $data);
        $data = preg_replace('#([a-z]*)[x00-x20]*=(['"]*)[x00-x20]*-moz-binding[x00-x20]*:#u', '$1=$2nomozbinding...', $data);

        // Only works in IE: &lt;span style="width: expression(alert('Ping!'));"&gt;&lt;/span&gt;
        $data = preg_replace('#(&lt;[^&gt;] ?)style[x00-x20]*=[x00-x20]*[`'"]*.*?expression[x00-x20]*([^&gt;]* &gt;#i', '$1&gt;', $data);
        $data = preg_replace('#(&lt;[^&gt;] ?)style[x00-x20]*=[x00-x20]*[`'"]*.*?behaviour[x00-x20]*([^&gt;]* &gt;#i', '$1&gt;', $data);
        $data = preg_replace('#(&lt;[^&gt;] ?)style[x00-x20]*=[x00-x20]*[`'"]*.*?s[x00-x20]*c[x00-x20]*r[x00-x20]*i[x00-x20]*p[x00-x20]*t[x00-x20]*:*[^&gt;]* &gt;#iu', '$1&gt;', $data);

        // Remove namespaced elements (we do not need them)
        $data = preg_replace('#&lt;/*w :w[^&gt;]* &gt;#i', '', $data);

        do
        {
            // Remove really unwanted tags
            $old_data = $data;
            $data = preg_replace('#&lt;/*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^&gt;]* &gt;#i', '', $data);
        }
        while ($old_data !== $data);

        return $data;
    }</pre>
<p>Then, we modified <tt>updateListItem()</tt> on line 239 to call the new method:</p>
<pre class="brush: php">        $newValue = $this-&gt;cleanInput(strip_tags(urldecode(trim($_POST["value"])), WHITELIST));</pre>
<p><strong><em>CATCH: This function appears to encode any non-English characters.  Foreign language users may see some unexpected behavior.</em></strong></p>
<h4>Cross-Site Request Forgeries</h4>
<p>Another risk we hadn&#8217;t considered when building this app was the possibility  that <strong>a malicious user could send bogus requests to our app</strong> by piggybacking on  a Colored Lists user&#8217;s session in a form of attack called  <a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery">Cross-Site  Request Forgeries</a> (CSRF). The snippet of JavaScript below, placed on any  site, would be executed if a user that was logged in to our app were to visit  the page. (Huge thanks to <a href="http://sketchpad.co.uk">Dan at  Sketchpad</a> for pointing this out and providing the above sample attack.)</p>
<pre class="brush: js">    &lt;script type="text/javascript"&gt;

        var form = document.createElement("form");
        form.setAttribute("method", "post");
        form.setAttribute("action", "http://coloredlists.com/db-interaction/users.php");

        var fields = new Array();
        fields["user-id"] = "158";
        fields["action"] = "deleteaccount";

        for(var key in fields)
        {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("type", "hidden");
            hiddenField.setAttribute("name", key);
            hiddenField.setAttribute("value", fields[key]);

            form.appendChild(hiddenField);
        }

        document.body.appendChild(form);
        form.submit();

    &lt;/script&gt;</pre>
<p>To remedy this, we need to <strong>generate a token to include with each form  submission that is also stored in the session.</strong> That way we can make sure the  two match before executing any requests. In doing this, CSRF is virtually  eliminated.</p>
<p>In <tt>/common/base.php</tt>, we added following at line 19:</p>
<pre class="brush: php">    if ( !isset($_SESSION['token']) )
    {
        $_SESSION['token'] = md5(uniqid(rand(), TRUE));
    }</pre>
<p>This creates a unique token for the user&#8217;s session. Then, on every form on our  site, we added the following hidden input:</p>
<pre class="brush: php">                &lt;input type="hidden" name="token"
                    value="&lt;?php echo $_SESSION['token']; ?&gt;" /&gt;</pre>
<p>And updated both <tt>/db-interaction/lists.inc.php</tt> and  <tt>/db-interactions/users.inc.php</tt> with the following starting at line 15:</p>
<pre class="brush: php">if ( $_POST['token'] == $_SESSION['token']
    &amp;&amp; !empty($_POST['action'])
    &amp;&amp; isset($_SESSION['LoggedIn'])
    &amp;&amp; $_SESSION['LoggedIn']==1 )</pre>
<p>Now any request made without a valid token will fail. For more on CSRF, visit  <a href="http://shiflett.org/articles/cross-site-request-forgeries">Chris  Shiflett&#8217;s blog</a>.</p>
<h4>Some Input Was Improperly Sanitized</h4>
<p>Above, we talked about the problem with blank email change requests breaking  accounts, and we created a method called <tt>validateUsername()</tt> that made  sure <strong>only valid email addresses were allowed to change an existing user email.</strong> That method looks like this:</p>
<pre class="brush: php">    /**
     * Verifies that a valid email address was passed
     *
     * @param string $email    The email address to check
     * @return mixed        The email address on success, FALSE on failure
     */
    private function validateUsername($email)
    {
        $pattern = "/^([ a-zA-Z0-9]) ([ a-zA-Z0-9._-])*@([a-zA-Z0-9_-]) ([a-zA-Z0-9._-] ) $/";
        $username = htmlentities(trim($email), ENT_QUOTES);
        return preg_match($pattern, $username) ? $username : FALSE;
    }</pre>
<p>Essentially, it uses a <a href="http://regular-expressions.info">regular  expression</a> to match the pattern of a valid email address, and either  returns the validated email address of boolean <tt>FALSE</tt>.</p>
<h3>Other Changes</h3>
<p>Aside from bugs and security patches, there were a couple parts of the site  that we just felt should have been better.</p>
<h4>Made Public URLs Tougher to Guess</h4>
<p>First, the original public list URLs were determined using  <a href="http://php.net/dechex"><tt>dechex()</tt></a>, and they were short and  easy to guess. We modified them to use MD5 instead to create <strong>longer, much more  difficult to guess public URLs.</strong> This happens right at the list&#8217;s creation when  the query calls <tt>SELECT MD5(UserID)</tt> in <tt>createAccount()</tt> on  line 100.</p>
<h4>Allowed &#8220;Safe&#8221; Links in List Items</h4>
<p>Some links are acceptable, and we felt that our app would be much more useful  if <strong>safe links were allowed in list items.</strong> To allow this, we simply removed the  call to <tt>strip_tags()</tt> in <tt>formatListItems()</tt> (found in  <tt>/inc/lists.inc.php</tt> on line 173):</p>
<pre class="brush: php">        return "tttt&lt;li id="$row[ListItemID]" rel="$order" "
            . "class="$c" color="$row[ListItemColor]"&gt;$ss"
            . $row['ListText'].$d
            . "$se&lt;/li&gt;n";</pre>
<p>The items are now sanitized on the way in, so we don&#8217;t need to worry about  them on the way out.</p>
<h3>Summary</h3>
<p>The steps we took above helped make our app more secure and dependable.  However, we know that nothing is ever perfect, so if you&#8217;ve got other bugs,  security holes, or suggestions, let us know in the comments!</p>
<div id="series-authors">
<h4>Series Authors</h4>
<div id="jason-series-author"><img style="margin: 0pt 10px 4px 0pt; float: left;" src="http://css-tricks.com/wp-content/csstricks-uploads/author-jason.jpg" alt="" width="125" height="125" /><strong>Jason Lengstorf</strong> is a software developer based in Missoula, MT. He is the author of <a href="http://www.amazon.com/gp/product/1430224738?ie=UTF8&amp;tag=ennudesi-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=1430224738">PHP for Absolute Beginners</a> and regularly blogs about programming. When not glued to his keyboard, he&rsquo;s likely standing in line for coffee, brewing his own beer, or daydreaming about being a Mythbuster.</div>
<div id="chris-series-author"><img style="margin: 0pt 0pt 4px 10px; float: right;" src="http://css-tricks.com/wp-content/csstricks-uploads/author-chris.jpg" alt="" width="125" height="125" /><strong>Chris Coyier</strong> is a designer currently living in Chicago, IL. He is the co-author of <a href="http://digwp.com/book/">Digging Into WordPress</a>, as well as blogger and speaker on all things design. Away from the computer, he is likely to be found yelling at Football coaches on TV or picking a banjo.</div>
</div>
<p>The post <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-9/">Creating an App from Scratch: Part 9</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-9/feed/</wfw:commentRss>
		<slash:comments>40</slash:comments>
		</item>
		<item>
		<title>Creating an App from Scratch Source Files and Giveaway Winner</title>
		<link>http://www.copterlabs.com/blog/creating-an-app-from-scratch-source-files/</link>
		<comments>http://www.copterlabs.com/blog/creating-an-app-from-scratch-source-files/#comments</comments>
		<pubDate>Fri, 04 Dec 2009 08:38:46 +0000</pubDate>
		<dc:creator>Jason Lengstorf</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Freebies & Giveaways]]></category>

		<guid isPermaLink="false">http://www.copterlabs.com/blog/creating-an-app-from-scratch-source-files</guid>
		<description><![CDATA[<p>Chris and I have packaged up the source code and PSD files for our Colored Lists web app and put them up on a splash page that includes navigation to the whole series. Creating a Web App from Scratch Homepage Also&#8230; <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-source-files/" class="more-link">More</a></p><p>The post <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-source-files/">Creating an App from Scratch Source Files and Giveaway Winner</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<p>Chris and I have packaged up the source code and PSD files for our <a href="http://coloredlists.com">Colored Lists</a> web app and put them up on a splash page that includes navigation to the whole series.</p>
<p><span class="demolink"><a href="http://css-tricks.com/examples/WebAppFromScratch/">Creating a Web App from Scratch Homepage</a></span></p>
<p>Also, we selected the five random winners for the book giveaway: congratulations to Bryan, gemmes, Gaston, An, and Mike Henderson. They&#8217;ll be receiving a free copy of <a href="http://www.amazon.com/gp/product/1430224738?ie=UTF8&amp;tag=ennudesi-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=1430224738"><em>PHP for Absolute Beginners</em></a>. If you didn&#8217;t win a copy, you can still save on <a href="http://apress.com/book/view/9781430224730">the ebook</a> with the discount code <strong>PHPXBRZQXSIKG</strong> (good through 12/31/2009).</p>
<p>Next week we&#8217;ll add a Part 9 to the series that will go over some of the bug fixes and security patches that were pointed out.</p>
<p>The post <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-source-files/">Creating an App from Scratch Source Files and Giveaway Winner</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.copterlabs.com/blog/creating-an-app-from-scratch-source-files/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Creating an App from Scratch: Part 7</title>
		<link>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-7/</link>
		<comments>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-7/#comments</comments>
		<pubDate>Thu, 26 Nov 2009 05:53:16 +0000</pubDate>
		<dc:creator>Jason Lengstorf</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-7</guid>
		<description><![CDATA[<p>Part 7 of the Creating an App from Scratch series, in which Chris Coyier and Jason Lengstorf explain the PHP and jQuery that make the application&#8217;s list handling functions work. <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-7/" class="more-link">More</a></p><p>The post <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-7/">Creating an App from Scratch: Part 7</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<div id="series-header"><img src="/assets/images/app-from-scratch/07-header.jpg" alt="Creating a Web App from Scratch Part 7" /></div>
<div id="series-navigation">
<h5>All Series Navigation</h5>
<ul>
<li><a href="http://css-tricks.com/app-from-scratch-1-design">Part 1 &ndash; Planning the App: Basic Idea and Design</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-2/">Part 2 &ndash; Planning the App: Database Architecture and Development Approach</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-3/">Part 3 &#8211; Designing the App: Workflow Map and Photoshop Design</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-4-html-css">Part 4 &#8211; Designing the App: HTML and CSS</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-5/">Part 5 &#8211; Developing the App: User Interaction</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-6-ajax">Part 6 &#8211; Developing the App: Adding AJAX Interactivity</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-7/">Part 7 &#8211; Developing the App: List Interaction</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-8-finishing">Part 8 &ndash; Wrapping Up</a></li>
<li> And finally&#8230; the application! <a href="http://coloredlists.com">Colored Lists</a></li>
</ul>
</div>
<h3>Where We&#8217;re At</h3>
<p>Now that we&#8217;ve got a set of AJAX controls mostly assembled, we can start  building our PHP class to <strong>handle list interactions.</strong> This class will be called  <tt>ColoredListsItems</tt> and it will reside in the file  <tt>class.lists.inc.php</tt> in the <tt>inc</tt> folder.</p>
<p>This class will contain methods to <strong>handle all of the actions performed by our  app or our users regarding list items.</strong> Namely, these actions are:</p>
<ul>
<li><strong>Displaying list items</strong></li>
<li><strong>Saving new list items</strong></li>
<li><strong>Reordering list items</strong></li>
<li><strong>Changing item colors</strong></li>
<li><strong>Editing item text</strong></li>
<li><strong>Marking an item as &#8220;done&#8221;</strong></li>
<li><strong>Deleting items</strong></li>
</ul>
<p>Also, because we need to be able to <strong>load a non-editable version of a list when  viewed from the public URL,</strong> we&#8217;ll need to add that functionality as well.</p>
<h3>Defining the Class</h3>
<p>Before we can do much of anything, we need to have our <tt>ColoredListsItems</tt> class  defined. Inside <tt>inc/class.lists.inc.php</tt>, add the following class declaration  and constructor:</p>
<pre class="brush: php">&lt;?php

/**
 * Handles list interactions within the app
 *
 * PHP version 5
 *
 * @author Jason Lengstorf
 * @author Chris Coyier
 * @copyright 2009 Chris Coyier and Jason Lengstorf
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 *
 */
class ColoredListsItems
{
    /**
     * The database object
     *
     * @var object
     */
    private $_db;

    /**
     * Checks for a database object and creates one if none is found
     *
     * @param object $db
     * @return void
     */
    public function __construct($db=NULL)
    {
        if(is_object($db))
        {
            $this-&gt;_db = $db;
        }
        else
        {
            $dsn = "mysql:host=".DB_HOST.";dbname=".DB_NAME;
            $this-&gt;_db = new PDO($dsn, DB_USER, DB_PASS);
        }
    }
}

?&gt;</pre>
<p>Notice that the constructor is identical to the one we used in  <tt>ColoredListsUsers</tt> (see <a href="/blog/creating-an-app-from-scratch-part-5/">Part 5&mdash;Developing the App: User Interaction</a>); it <strong>checks  for a database object and creates one if none are available. </strong></p>
<h3>Displaying List Items</h3>
<p>Even though we don&#8217;t currently have any items saved in our database, we know  what they&#8217;re going to look like. With that in mind, we can <strong>write our output  functions</strong> to display our list items to users, both in a logged in and logged  out state.</p>
<h4>If the User Is Logged In</h4>
<p>When our user is logged in, we&#8217;ll be loading their list by their user name.  This user name is stored in the <a href="http://us.php.net/manual/en/reserved.variables.session.php"><tt>$_SESSION</tt> superglobal</a>.</p>
<p>In <tt>inc/class.lists.inc.php</tt>, define the method <tt>loadListItemsByUser()</tt> and insert  the following code:</p>
<pre class="brush: php">class ColoredListsItems
{
    // Class properties and other methods omitted to save space


    /**
     * Loads all list items associated with a user ID
     *
     * This function both outputs &lt;li&gt; tags with list items and returns an
     * array with the list ID, list URL, and the order number for a new item.
     *
     * @return array    an array containing list ID, list URL, and next order
     */
    public function loadListItemsByUser()
    {
        $sql = "SELECT
                    list_items.ListID, ListText, ListItemID, ListItemColor,
                    ListItemDone, ListURL
                FROM list_items
                LEFT JOIN lists
                USING (ListID)
                WHERE list_items.ListID=(
                    SELECT lists.ListID
                    FROM lists
                    WHERE lists.UserID=(
                        SELECT users.UserID
                        FROM users
                        WHERE users.Username=:user
                    )
                )
                ORDER BY ListItemPosition";
        if($stmt = $this-&gt;_db-&gt;prepare($sql))
        {
            $stmt-&gt;bindParam(':user', $_SESSION['Username'], PDO::PARAM_STR);
            $stmt-&gt;execute();
            $order = 0;
            while($row = $stmt-&gt;fetch())
            {
                $LID = $row['ListID'];
                $URL = $row['ListURL'];
                echo $this-&gt;formatListItems($row,   $order);
            }
            $stmt-&gt;closeCursor();

            // If there aren't any list items saved, no list ID is returned
            if(!isset($LID))
            {
                $sql = "SELECT ListID, ListURL
                        FROM lists
                        WHERE UserID = (
                            SELECT UserID
                            FROM users
                            WHERE Username=:user
                        )";
                if($stmt = $this-&gt;_db-&gt;prepare($sql))
                {
                    $stmt-&gt;bindParam(':user', $_SESSION['Username'], PDO::PARAM_STR);
                    $stmt-&gt;execute();
                    $row = $stmt-&gt;fetch();
                    $LID = $row['ListID'];
                    $URL = $row['ListURL'];
                    $stmt-&gt;closeCursor();
                }
            }
        }
        else
        {
            echo "tttt&lt;li&gt; Something went wrong. ", $db-&gt;errorInfo, "&lt;/li&gt;n";
        }

        return array($LID, $URL, $order);
    }
}</pre>
<p>This method starts with a somewhat complex query that <strong>starts by <a href="http://dev.mysql.com/doc/refman/5.0/en/join.html">joining</a> the </strong><tt>list_items</tt><strong> and </strong><tt>lists</tt> <strong>tables, then uses a sub-query to filter the list items  by user ID. </strong></p>
<p>If the query returns results, we <strong>loop through them and call the  yet-to-be-defined </strong><tt>formatListItems()</tt> <strong>method.</strong> Each formatted item is output  immediately using <tt>echo()</tt>, and the list ID and URL are saved.</p>
<p>If no results are returned (meaning the user doesn&#8217;t have any items on their  list), the list ID and URL won&#8217;t be returned. However, we need this  information in order to allow users to submit new items and share their lists.  A check is in place to see if the list ID variable (<tt>$LID</tt>) is set. <strong>If not, an  additional query is executed to retrieve the user&#8217;s list ID and URL. </strong></p>
<p>The list ID and URL are then returned as an array.</p>
<h4>If the User Is Not Logged In</h4>
<p>If no user is logged in, <em>we don&#8217;t have access to a user name with which to  load the items.</em> Therefore, <strong>we need to use the list&#8217;s ID to load items.</strong> We&#8217;re  able to determine the list&#8217;s ID using the list&#8217;s URL, which is the only way a  user who isn&#8217;t logged in will be able to view a list in the first place. The  method looks like this in <tt>inc/class.lists.inc.php</tt>:</p>
<pre class="brush: php">class ColoredListsItems
{
    // Class properties and other methods omitted to save space


    /**
     * Outputs all list items corresponding to a particular list ID
     *
     * @return void
     */
    public function loadListItemsByListId()
    {
        $sql = "SELECT ListText, ListItemID, ListItemColor, ListItemDone
                FROM list_items
                WHERE ListID=(
                    SELECT ListID
                    FROM lists
                    WHERE ListURL=:list
                )
                ORDER BY ListItemPosition";
        if($stmt = $this-&gt;_db-&gt;prepare($sql)) {
            $stmt-&gt;bindParam(':list', $_GET['list'], PDO::PARAM_STR);
            $stmt-&gt;execute();
            $order = 1;
            while($row = $stmt-&gt;fetch())
            {
                echo $this-&gt;formatListItems($row, $order);
                  $order;
            }
            $stmt-&gt;closeCursor();
        } else {
            echo "&lt;li&gt; Something went wrong. ", $db-&gt;error, "&lt;/li&gt;";
        }
    }
}</pre>
<h4>Formatting List Items</h4>
<p>To make our previous two methods work properly, we also need to define our  <tt>formatListItems()</tt> method. This method is fairly straightforward, <em>but it also  needs a helper method</em> to determine the CSS class for each item, which we&#8217;ll  call <tt>getColorClass()</tt>. This helper method only exists to simplify our code.  Insert both methods into <tt>inc/class.lists.inc.php</tt> as follows:</p>
<pre class="brush: php">class ColoredListsItems
{
    // Class properties and other methods omitted to save space


    /**
     * Generates HTML markup for each list item
     *
     * @param array $row    an array of the current item's attributes
     * @param int $order    the position of the current list item
     * @return string       the formatted HTML string
     */
    private function formatListItems($row, $order)
    {
        $c = $this-&gt;getColorClass($row['ListItemColor']);
        if($row['ListItemDone']==1)
        {
            $d = '&lt;img class="crossout" src="/assets/images/crossout.png" '
                . 'style="width: 100%; display: block;"/&gt;';
        }
        else
        {
            $d = NULL;
        }

        // If not logged in, manually append the &lt;span&gt; tag to each item
        if(!isset($_SESSION['LoggedIn'])||$_SESSION['LoggedIn']!=1)
        {
            $ss = "&lt;span&gt;";
            $se = "&lt;/span&gt;";
        }
        else
        {
            $ss = NULL;
            $se = NULL;
        }

        return "tttt&lt;li id="$row[ListItemID]" rel="$order" "
            . "class="$c" color="$row[ListItemColor]"&gt;$ss"
            . htmlentities(strip_tags($row['ListText'])).$d
            . "$se&lt;/li&gt;n";
    }

    /**
     * Returns the CSS class that determines color for the list item
     *
     * @param int $color    the color code of an item
     * @return string       the corresponding CSS class for the color code
     */
    private function getColorClass($color)
    {
        switch($color)
        {
            case 1:
                return 'colorBlue';
            case 2:
                return 'colorYellow';
            case 3:
                return 'colorRed';
            default:
                return 'colorGreen';
        }
    }
}</pre>
<p>An array containing each list item&#8217;s attributes is passed to  <tt>formatListItems()</tt>, and <strong>different attributes are created depending on the  values that are passed.</strong> If a user isn&#8217;t logged in, we manually append a  <tt>&lt;span&gt;</tt> to the markup to keep our CSS from breaking, and then we wrap the  whole thing in a <tt>&lt;li&gt;</tt> and return it.</p>
<h4>Calling Our New Methods in the Main View</h4>
<p>Our main page (<tt>index.php</tt>) currently has notes from the designer that look like  this:</p>
<pre class="brush: php">&lt;div id="main"&gt;


   &lt;noscript&gt;This site just doesn't work, period, without JavaScript&lt;/noscript&gt;


   &lt;!-- IF LOGGED IN --&gt;

          &lt;!-- Content here --&gt;


   &lt;!-- IF LOGGED OUT --&gt;

          &lt;!-- Alternate content here --&gt;


&lt;/div&gt;</pre>
<p>In order to make these notes into a functional script, we need to add the  following logic to <tt>index.php</tt> to call the proper methods:</p>
<pre class="brush: php">        &lt;div id="main"&gt;
            &lt;noscript&gt;This site just doesn't work, period, without JavaScript&lt;/noscript&gt;
&lt;?php
if(isset($_SESSION['LoggedIn']) &amp;&amp; isset($_SESSION['Username'])):
    echo "ttt&lt;ul id="list"&gt;n";

    include_once 'inc/class.lists.inc.php';
    $lists = new ColoredListsItems($db);
    list($LID, $URL, $order) = $lists-&gt;loadListItemsByUser();

    echo "ttt&lt;/ul&gt;";
?&gt;

            &lt;br /&gt;

            &lt;form action="db-interaction/lists.php" id="add-new" method="post"&gt;
                &lt;input type="text" id="new-list-item-text" name="new-list-item-text" /&gt;

                &lt;input type="hidden" id="current-list" name="current-list" value="&lt;?php echo $LID; ?&gt;" /&gt;
                &lt;input type="hidden" id="new-list-item-position" name="new-list-item-position" value="&lt;?php echo   $order; ?&gt;" /&gt;

                &lt;input type="submit" id="add-new-submit" value="Add" class="button" /&gt;
            &lt;/form&gt;

            &lt;div class="clear"&gt;&lt;/div&gt;

            &lt;div id="share-area"&gt;
                &lt;p&gt;Public list URL: &lt;a target="_blank" href="http://coloredlists.com/&lt;?php echo $URL ?&gt;.html"&gt;http://coloredlists.com/&lt;?php echo $URL ?&gt;.html&lt;/a&gt;
                &amp;nbsp; &lt;small&gt;(Nobody but YOU will be able to edit this list)&lt;/small&gt;&lt;/p&gt;
            &lt;/div&gt;

            &lt;script type="text/javascript" src="js/jquery-ui-1.7.2.custom.min.js"&gt;&lt;/script&gt;
            &lt;script type="text/javascript" src="js/jquery.jeditable.mini.js"&gt;&lt;/script&gt;
            &lt;script type="text/javascript" src="js/lists.js"&gt;&lt;/script&gt;
            &lt;script type="text/javascript"&gt;
                initialize();
            &lt;/script&gt;

&lt;?php
elseif(isset($_GET['list'])):
    echo "ttt&lt;ul id='list'&gt;n";

    include_once 'inc/class.lists.inc.php';
    $lists = new ColoredListsItems($db);
    list($LID, $URL) = $lists-&gt;loadListItemsByListId();

    echo "ttt&lt;/ul&gt;";
else:
?&gt;

            &lt;img src="/assets/images/newlist.jpg" alt="Your new list here!" /&gt;

&lt;?php endif; ?&gt;

        &lt;/div&gt;</pre>
<p>This script <strong>checks if a user is logged in, then outputs their list and the  proper controls if so.</strong> If not, we check if there was a list URL supplied and  outputs a non-editable list if one is found. Otherwise, the &#8220;sales&#8221; page is  displayed, encouraging the viewer to sign up.</p>
<h3>Saving New List Items</h3>
<p>At this point, our app will function properly for a user that is logged in.  Now we just need to plug in the controls that will allow him or her to  interact with the list. First, we need to <strong>allow for new items to be created.</strong> To do this, we need to write a PHP method that will add list items to our  database, and then we need to complete the jQuery started by our designer in  <a href="http://css-tricks.com/app-from-scratch-6-ajax/">Part 6</a>.</p>
<h4>The PHP</h4>
<p>Saving an item is simple enough on the server side. We simply grab all of the  new item&#8217;s information out of the <tt>$_POST</tt> superglobal, prepare a statement, and  save the info in the database. Note that we&#8217;re running <tt>strip_tags()</tt> on the  list item&#8217;s text. <strong>This is a redundant check since we&#8217;re using JavaScript to  remove any unwanted tags, but we shouldn&#8217;t rely on data that was sanitized  client-side.</strong></p>
<pre class="brush: php">class ColoredListsItems
{
    // Class properties and other methods omitted to save space


    /**
     * Adds a list item to the database
     *
     * @return mixed    ID of the new item on success, error message on failure
     */
    public function addListItem()
    {
        $list = $_POST['list'];
        $text = strip_tags(urldecode(trim($_POST['text'])), WHITELIST);
        $pos = $_POST['pos'];

        $sql = "INSERT INTO list_items
                    (ListID, ListText, ListItemPosition, ListItemColor)
                VALUES (:list, :text, :pos, 1)";
        try
        {
            $stmt = $this-&gt;_db-&gt;prepare($sql);
            $stmt-&gt;bindParam(':list', $list, PDO::PARAM_INT);
            $stmt-&gt;bindParam(':text', $text, PDO::PARAM_STR);
            $stmt-&gt;bindParam(':pos', $pos, PDO::PARAM_INT);
            $stmt-&gt;execute();
            $stmt-&gt;closeCursor();

            return $this-&gt;_db-&gt;lastInsertId();
        }
        catch(PDOException $e)
        {
            return $e-&gt;getMessage();
        }
    }
}</pre>
<p>Notice that we used a constant called <tt>WHITELIST</tt> in the <tt>strip_tags()</tt> function. <strong> This is a list of allowed tags that our users have access to.</strong> However, we  should assume that we&#8217;ll want to change this list at some point in the future,  which is why we&#8217;re saving the list as a constant, which we&#8217;ll define in  <tt>inc/constants.inc.php</tt>:</p>
<pre class="brush: php">    // HTML Whitelist
    define('WHITELIST', '&lt;b&gt;&lt;i&gt;&lt;strong&gt;&lt;em&gt;&lt;a&gt;');</pre>
<h4>Finishing the JavaScript</h4>
<p>To complete the jQuery in <tt>js/lists.js</tt>, we need to modify the script with the  code below:</p>
<pre class="brush: js">    // AJAX style adding of list items
    $('#add-new').submit(function(){
        // HTML tag whitelist. All other tags are stripped.
        var $whitelist = '&lt;b&gt;&lt;i&gt;&lt;strong&gt;&lt;em&gt;&lt;a&gt;',
            forList = $("#current-list").val(),
            newListItemText = strip_tags(cleanHREF($("#new-list-item-text").val()), $whitelist),
            URLtext = escape(newListItemText),
            newListItemRel = $('#list li').size() 1;

        if(newListItemText.length &gt; 0) {
            $.ajax({
                type: "POST",
                url: "db-interaction/lists.php",
                data: "action=add&amp;list="   forList   "&amp;text="   URLtext   "&amp;pos="   newListItemRel,
                success: function(theResponse){
                  $("#list").append("&lt;li color='1' class='colorBlue' rel='" newListItemRel "' id='"   theResponse   "'&gt;&lt;span id="" theResponse "listitem" title='Click to edit...'&gt;"   newListItemText   "&lt;/span&gt;&lt;div class='draggertab tab'&gt;&lt;/div&gt;&lt;div class='colortab tab'&gt;&lt;/div&gt;&lt;div class='deletetab tab'&gt;&lt;/div&gt;&lt;div class='donetab tab'&gt;&lt;/div&gt;&lt;/li&gt;");
                  bindAllTabs("#list li[rel='" newListItemRel "'] span");
                  $("#new-list-item-text").val("");
                },
                error: function(){
                    // uh oh, didn't work. Error message?
                }
            });
        } else {
            $("#new-list-item-text").val("");
        }
        return false; // prevent default form submission
    });</pre>
<p>We&#8217;re completing the <tt>$.ajax()</tt> call by submitting the new item via the <tt>POST</tt> method to <tt>db-interation/lists.php</tt>. <strong>The successfully added item is then  appended to our list, all without a page refresh. </strong></p>
<h4>Handling List Interactions</h4>
<p>Our <tt>$.ajax()</tt> call sends to <tt>db-interaction/lists.php</tt>, which doesn&#8217;t exist yet.<strong> This script acts as a switch that will determine what action is needed and  execute the proper method.</strong> All requests are handled the same way, so  let&#8217;s just define the whole file here. Create new file called <tt>lists.php</tt> in the  <tt>db-interaction</tt> folder and insert the following code into it:</p>
<pre class="brush: php">&lt;?php

session_start();

include_once "../inc/constants.inc.php";
include_once "../inc/class.lists.inc.php";

if(!empty($_POST['action'])
&amp;&amp; isset($_SESSION['LoggedIn'])
&amp;&amp; $_SESSION['LoggedIn']==1)
{
    $listObj = new ColoredListsItems();
    switch($_POST['action'])
    {
        case 'add':
            echo $listObj-&gt;addListItem();
            break;
        case 'update':
            $listObj-&gt;updateListItem();
            break;
        case 'sort':
            $listObj-&gt;changeListItemPosition();
            break;
        case 'color':
            echo $listObj-&gt;changeListItemColor();
            break;
        case 'done':
            echo $listObj-&gt;toggleListItemDone();
            break;
        case 'delete':
            echo $listObj-&gt;deleteListItem();
            break;
        default:
            header("Location: /");
            break;
    }
}
else
{
    header("Location: /");
    exit;
}

?&gt;</pre>
<h3>Reordering List Items</h3>
<p>Next, we need to <strong>allow users to save the order of their items</strong> after they&#8217;ve  dragged and dropped them. <em>This is definitely the most complex part of our  whole app.</em></p>
<h4>The PHP</h4>
<p><strong> Each item is assigned a position when it&#8217;s read out of the database.</strong> This is  the item&#8217;s <em>starting position</em>. When it is dragged, it ends up in a new place in  the list; we&#8217;re going to call this new position it&#8217;s <em>current position</em>.</p>
<p>When <tt>changeListItemPosition()</tt> is called, both the item&#8217;s starting position and  current position are passed, as well as the direction it moved. <strong>This is where  it gets tricky. </strong></p>
<p>Depending on the direction the item was moved, we set up one of two  conditional queries. We <strong>select all the items in the current list with a  position falling between the starting and current positions</strong>, then, using the <a href="http://dev.mysql.com/doc/refman/5.0/en/case-statement.html"> <tt>CASE</tt> clause</a>, increment or decrement their positions by <tt>1</tt> <strong>unless the item&#8217;s  position plus or minus one falls outside the range we&#8217;ve selected, at which  point we set the item&#8217;s position to the current position.</strong> In this way, we&#8217;re  able to avoid firing an individual query for each item, which could potentially cause a performance bottleneck.</p>
<pre class="brush: php">class ColoredListsItems
{
    // Class properties and other methods omitted to save space


    /**
     * Changes the order of a list's items
     *
     * @return string    a message indicating the number of affected items
     */
    public function changeListItemPosition()
    {
        $listid = (int) $_POST['currentListID'];
        $startPos = (int) $_POST['startPos'];
        $currentPos = (int) $_POST['currentPos'];
        $direction = $_POST['direction'];

        if($direction == 'up')
        {
            /*
             * This query modifies all items with a position between the item's
             * original position and the position it was moved to. If the
             * change makes the item's position greater than the item's
             * starting position, then the query sets its position to the new
             * position. Otherwise, the position is simply incremented.
             */
            $sql = "UPDATE list_items
                    SET ListItemPosition=(
                        CASE
                            WHEN ListItemPosition 1&gt;$startPos THEN $currentPos
                            ELSE ListItemPosition 1
                        END)
                    WHERE ListID=$listid
                    AND ListItemPosition BETWEEN $currentPos AND $startPos";
        }
        else
        {
            /*
             * Same as above, except item positions are decremented, and if the
             * item's changed position is less than the starting position, its
             * position is set to the new position.
             */
            $sql = "UPDATE list_items
                    SET ListItemPosition=(
                        CASE
                            WHEN ListItemPosition-1&lt;$startPos THEN $currentPos
                            ELSE ListItemPosition-1
                        END)
                    WHERE ListID=$listid
                    AND ListItemPosition BETWEEN $startPos AND $currentPos";
        }

        $rows = $this-&gt;_db-&gt;exec($sql);
        echo "Query executed successfully. ",
            "Affected rows: $rows";
    }
}</pre>
<h4>Finishing the JavaScript</h4>
<p>To call our method, we need to modify <tt>js/lists.js</tt> by adding a new function  called <tt>saveListOrder()</tt>:</p>
<pre class="brush: js">function saveListOrder(itemID, itemREL){
    var i = 1,
        currentListID = $('#current-list').val();
    $('#list li').each(function() {
        if($(this).attr('id') == itemID) {
            var startPos = itemREL,
                currentPos = i;
            if(startPos &lt; currentPos) {
                var direction = 'down';
            } else {
                var direction = 'up';
            }
            var postURL = "action=sort&amp;currentListID=" currentListID
                 "&amp;startPos=" startPos
                 "&amp;currentPos=" currentPos
                 "&amp;direction=" direction;

            $.ajax({
                type: "POST",
                url: "db-interaction/lists.php",
                data: postURL,
                success: function(msg) {
                    // Resets the rel attribute to reflect current positions
                    var count=1;
                    $('#list li').each(function() {
                        $(this).attr('rel', count);
                        count  ;
                    });
                },
                error: function(msg) {
                    // error handling here
                }
            });
        }
        i  ;
    });
}</pre>
<p>This function accepts the ID and rel attribute of the item that was moved. The  rel attribute contains the original position of the item, which we need as its  starting position. Then we <strong>loop through each list item while incrementing a  counter</strong> (<tt>i</tt>). When we find the list item that matches the moved item&#8217;s ID, our  counter now reflects the item&#8217;s current position. We can then determine which  direction the item was moved and send the info to <tt>db-interaction/lists.php</tt> for  processing.</p>
<p>This function needs to be called when a sortable item is updated, which we  accomplish by modifying the following in <tt>js/lists.js</tt>:</p>
<pre class="brush: js">    // MAKE THE LIST SORTABLE VIA JQUERY UI
    // calls the SaveListOrder function after a change
    // waits for one second first, for the DOM to set, otherwise it's too fast.
    $("#list").sortable({
        handle   : ".draggertab",
        update   : function(event, ui){
            var id = ui.item.attr('id');
            var rel = ui.item.attr('rel');
            var t = setTimeout("saveListOrder('" id "', '" rel "')",500);
        },
        forcePlaceholderSize: true
    });</pre>
<h3>Changing Item Colors</h3>
<p>Changing an item&#8217;s color is fairly simple on both the server- and client-side.</p>
<h4>The PHP</h4>
<p>To update an item&#8217;s color, we simply <strong>pass it&#8217;s ID and the new color code to  the method </strong><tt>changeListItemColor()</tt> <strong>and create and execute a query.</strong></p>
<pre class="brush: php">class ColoredListsItems
{
    // Class properties and other methods omitted to save space


    /**
     * Changes the color code of a list item
     *
     * @return mixed    returns TRUE on success, error message on failure
     */
    public function changeListItemColor()
    {
        $sql = "UPDATE list_items
                SET ListItemColor=:color
                WHERE ListItemID=:item
                LIMIT 1";
        try
        {
            $stmt = $this-&gt;_db-&gt;prepare($sql);
            $stmt-&gt;bindParam(':color', $_POST['color'], PDO::PARAM_INT);
            $stmt-&gt;bindParam(':item', $_POST['id'], PDO::PARAM_INT);
            $stmt-&gt;execute();
            $stmt-&gt;closeCursor();
            return TRUE;
        } catch(PDOException $e) {
            return $e-&gt;getMessage();
        }
    }
}</pre>
<h4>Finishing the JavaScript</h4>
<p>The function that saves new colors is called by submitting the item ID and new  color via <tt>POST</tt> in the <tt>$.ajax()</tt> call below in <tt>js/lists.js</tt>:</p>
<pre class="brush: js">    // COLOR CYCLING
    // Does AJAX save, but no visual feedback
    $(".colortab").live("click", function(){
        $(this).parent().nextColor();

        var id = $(this).parent().attr("id"),
            color = $(this).parent().attr("color");

        $.ajax({
            type: "POST",
            url: "db-interaction/lists.php",
            data: "action=color&amp;id="   id   "&amp;color="   color,
            success: function(msg) {
                // error message
            }
        });
    });</pre>
<h3>Editing Item Text</h3>
<p>Next, let&#8217;s make sure edited items are updated in the database.</p>
<h4>The PHP</h4>
<p>To save updated items in the database, we need to create a method called  <tt>updateListItem()</tt>. This method will <strong>extract the ID of the modified item and the  new text from the</strong> <tt>$_POST</tt> <strong>superglobal, double-check the item text for  disallowed tags, and prepare and execute a query to update the item in the  database.</strong> Add the following method in <tt>inc/class.lists.inc.php</tt>:</p>
<pre class="brush: php">class ColoredListsItems
{
    // Class properties and other methods omitted to save space


    /**
     * Updates the text for a list item
     *
     * @return string    Sanitized saved text on success, error message on fail
     */
    public function updateListItem()
    {
        $listItemID = $_POST["listItemID"];
        $newValue = strip_tags(urldecode(trim($_POST["value"])), WHITELIST);

        $sql = "UPDATE list_items
                SET ListText=:text
                WHERE ListItemID=:id
                LIMIT 1";
        if($stmt = $this-&gt;_db-&gt;prepare($sql)) {
            $stmt-&gt;bindParam(':text', $newValue, PDO::PARAM_STR);
            $stmt-&gt;bindParam(':id', $listItemID, PDO::PARAM_INT);
            $stmt-&gt;execute();
            $stmt-&gt;closeCursor();

            echo $newValue;
        } else {
            echo "Error saving, sorry about that!";
        }
    }
}</pre>
<h4>Finishing the JavaScript</h4>
<p>Activate this method by modifying the path in <tt>bindAllTabs()</tt> in <tt>js/lists.js</tt>:</p>
<pre class="brush: js">// This is seperated to a function so that it can be called at page load
// as well as when new list items are appended via AJAX
function bindAllTabs(editableTarget) {

    // CLICK-TO-EDIT on list items
    $(editableTarget).editable("db-interaction/lists.php", {
        id        : 'listItemID',
        indicator : 'Saving...',
        tooltip   : 'Double-click to edit...',
        event     : 'dblclick',
        submit    : 'Save',
        submitdata: {action : "update"}
    });

}</pre>
<h3>Marking Items as &#8220;Done&#8221;</h3>
<p>To mark an item as done, the user needs to be able to save a flag in the  database that will indicate the item&#8217;s &#8220;done&#8221; status.</p>
<h4>The PHP</h4>
<p>The <tt>toggleListItemDone()</tt> method <strong>retrieves the item&#8217;s ID and &#8220;done&#8221; status from  the</strong> <tt>$_POST</tt> <strong>superglobal and uses them to update the item in the database:</strong></p>
<pre class="brush: php">class ColoredListsItems
{
    // Class properties and other methods omitted to save space


    /**
     * Changes the ListItemDone state of an item
     *
     * @return mixed    returns TRUE on success, error message on failure
     */
    public function toggleListItemDone()
    {
        $sql = "UPDATE list_items
                SET ListItemDone=:done
                WHERE ListItemID=:item
                LIMIT 1";
        try
        {
            $stmt = $this-&gt;_db-&gt;prepare($sql);
            $stmt-&gt;bindParam(':done', $_POST['done'], PDO::PARAM_INT);
            $stmt-&gt;bindParam(':item', $_POST['id'], PDO::PARAM_INT);
            $stmt-&gt;execute();
            $stmt-&gt;closeCursor();
            return TRUE;
        } catch(PDOException $e) {
            return $e-&gt;getMessage();
        }
    }
}</pre>
<h4>Finishing the JavaScript</h4>
<p>To call our method, we write a function called <tt>toggleDone()</tt> in <tt>js/lists.js</tt>.  This function simply executes a call to the <tt>$.ajax()</tt> function and sends the  item ID and &#8220;done&#8221; status to our list handler.</p>
<pre class="brush: js">    function toggleDone(id, isDone)
    {
        $.ajax({
            type: "POST",
            url: "db-interaction/lists.php",
            data: "action=done&amp;id=" id "&amp;done=" isDone
        })
    }</pre>
<p>Next, we assign <tt>toggleDone()</tt> as the callback function for the <tt>animate()</tt> even  that happens when our user clicks the done tab:</p>
<pre class="brush: js">    $(".donetab").live("click", function() {
        var id = $(this).parent().attr('id');
        if(!$(this).siblings('span').children('img.crossout').length)
        {
            $(this)
                .parent()
                    .find("span")
                    .append("&lt;img src='/images/crossout.png' class='crossout' /&gt;")
                    .find(".crossout")
                    .animate({
                        width: "100%"
                    })
                    .end()
                .animate({
                    opacity: "0.5"
                },
                "slow",
                "swing",
                toggleDone(id, 1));
        }
        else
        {
            $(this)
                .siblings('span')
                    .find('img.crossout')
                        .remove()
                        .end()
                    .animate({
                        opacity : 1
                    },
                    "slow",
                    "swing",
                    toggleDone(id, 0));

        }
    });</pre>
<h3>Deleting Items</h3>
<p>Finally, we need to allow our users to delete items that they no longer want  on their list.</p>
<h4>The PHP</h4>
<p>To delete an item, we need to create a method called <tt>deleteListItem()</tt> in  <tt>inc/class.lists.inc.php</tt>. This method will <strong>retrieve the item and list IDs from  the</strong> <tt>$_POST</tt> <strong>superglobal, then remove the item from the list.</strong> Then, to preserve  proper order in the list, <strong>all items in the list with a position higher than  that of the item that was deleted need to be decremented by 1. </strong></p>
<pre class="brush: php">class ColoredListsItems
{
    // Class properties and other methods omitted to save space


    /**
     * Removes a list item from the database
     *
     * @return string    message indicating success or failure
     */
    public function deleteListItem()
    {
        $list = $_POST['list'];
        $item = $_POST['id'];

        $sql = "DELETE FROM list_items
                WHERE ListItemID=:item
                AND ListID=:list
                LIMIT 1";
        try
        {
            $stmt = $this-&gt;_db-&gt;prepare($sql);
            $stmt-&gt;bindParam(':item', $item, PDO::PARAM_INT);
            $stmt-&gt;bindParam(':list', $list, PDO::PARAM_INT);
            $stmt-&gt;execute();
            $stmt-&gt;closeCursor();

            $sql = "UPDATE list_items
                    SET ListItemPosition=ListItemPosition-1
                    WHERE ListID=:list
                    AND ListItemPosition&gt;:pos";
            try
            {
                $stmt = $this-&gt;_db-&gt;prepare($sql);
                $stmt-&gt;bindParam(':list', $list, PDO::PARAM_INT);
                $stmt-&gt;bindParam(':pos', $_POST['pos'], PDO::PARAM_INT);
                $stmt-&gt;execute();
                $stmt-&gt;closeCursor();
                return "Success!";
            }
            catch(PDOException $e)
            {
                return $e-&gt;getMessage();
            }
        }
        catch(Exception $e)
        {
            return $e-&gt;getMessage();
        }
    }
}</pre>
<h4>Finishing the JavaScript</h4>
<p>To activate this method, we need to modify our jQuery by updating the section  in <tt>js/lists.js</tt> that deals with item deletion:</p>
<pre class="brush: js">    // AJAX style deletion of list items
    $(".deletetab").live("click", function(){
        var thiscache = $(this),
            list = $('#current-list').val(),
            id = thiscache.parent().attr("id"),
            pos = thiscache.parents('li').attr('rel');

        if (thiscache.data("readyToDelete") == "go for it") {
            $.ajax({
                type: "POST",
                url: "db-interaction/lists.php",
                data: {
                        "list":list,
                        "id":id,
                        "action":"delete",
                        "pos":pos
                    },
                success: function(r){
                        var $li = $('#list').children('li'),
                            position = 0;
                        thiscache
                            .parent()
                                .hide("explode", 400, function(){$(this).remove()});
                        $('#list')
                            .children('li')
                                .not(thiscache.parent())
                                .each(function(){
                                        $(this).attr('rel',   position);
                                    });
                    },
                error: function() {
                    $("#main").prepend("Deleting the item failed...");
                }
            });
        }
        else
        {
            thiscache.animate({
                width: "44px",
                right: "-64px"
            }, 200)
            .data("readyToDelete", "go for it");
        }
    });</pre>
<h3>Moving On</h3>
<p>We have now succeeded in building all of the AJAX functionality for our app!  There was a ton of information in this article, and we went through it rather  quickly, so <strong>please post any questions you have in the comments! </strong></p>
<p>In the final installment of this series, we&#8217;ll go over the <strong>security measures  and other finishing touches</strong> this app needs to be ready for public use. We&#8217;ll  also go over some of the features we hope to add in the future.</p>
<div id="series-authors">
<h4>Series Authors</h4>
<div id="jason-series-author"><img style="margin: 0pt 10px 4px 0pt; float: left;" src="http://css-tricks.com/wp-content/csstricks-uploads/author-jason.jpg" alt="" width="125" height="125" /><strong>Jason Lengstorf</strong> is a software developer based in Missoula, MT. He is the author of <a href="http://www.amazon.com/gp/product/1430224738?ie=UTF8&amp;tag=ennudesi-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=1430224738">PHP for Absolute Beginners</a> and regularly blogs about programming. When not glued to his keyboard, he&rsquo;s likely standing in line for coffee, brewing his own beer, or daydreaming about being a Mythbuster.</div>
<div id="chris-series-author"><img style="margin: 0pt 0pt 4px 10px; float: right;" src="http://css-tricks.com/wp-content/csstricks-uploads/author-chris.jpg" alt="" width="125" height="125" /><strong>Chris Coyier</strong> is a designer currently living in Chicago, IL. He is the co-author of <a href="http://digwp.com/book/">Digging Into WordPress</a>, as well as blogger and speaker on all things design. Away from the computer, he is likely to be found yelling at Football coaches on TV or picking a banjo.</div>
</div>
<p>The post <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-7/">Creating an App from Scratch: Part 7</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-7/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Creating an App from Scratch: Part 5</title>
		<link>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-5/</link>
		<comments>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-5/#comments</comments>
		<pubDate>Wed, 25 Nov 2009 06:08:06 +0000</pubDate>
		<dc:creator>Jason Lengstorf</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-5</guid>
		<description><![CDATA[<p>Part 5 of the Creating an App from Scratch series, in which Chris Coyier and Jason Lengstorf go over the PHP and MySQL that handles the creation and updating of user accounts. <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-5/" class="more-link">More</a></p><p>The post <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-5/">Creating an App from Scratch: Part 5</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<div id="series-header"><img src="/assets/images/app-from-scratch/05-header.jpg" alt="Creating a Web App from Scratch Part 5" /></div>
<div id="series-navigation">
<h5>All Series Navigation</h5>
<ul>
<li><a href="http://css-tricks.com/app-from-scratch-1-design">Part 1 &ndash; Planning the App: Basic Idea and Design</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-2/">Part 2 &ndash; Planning the App: Database Architecture and Development Approach</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-3/">Part 3 &#8211; Designing the App: Workflow Map and Photoshop Design</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-4-html-css">Part 4 &#8211; Designing the App: HTML and CSS</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-5/">Part 5 &#8211; Developing the App: User Interaction</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-6-ajax">Part 6 &#8211; Developing the App: Adding AJAX Interactivity</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-7/">Part 7 &#8211; Developing the App: List Interaction</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-8-finishing">Part 8 &ndash; Wrapping Up</a></li>
<li> And finally&#8230; the application! <a href="http://coloredlists.com">Colored Lists</a></li>
</ul>
</div>
<h3>Where Are We?</h3>
<p>Now that we have a workflow put together and the HTML and CSS to make it look  good, we can actually <strong>start building the classes</strong> that will run this puppy.</p>
<p>We&#8217;ll focus this installment of the series on the <strong>user&#8217;s account interactions.</strong> These include:</p>
<ul>
<li><strong>Creating an Account</strong></li>
<li><strong>Modifying Account Information</strong></li>
<li><strong>Resetting a Lost Password</strong></li>
<li><strong>Deleting an Account</strong></li>
</ul>
<h3>Connecting to the Database</h3>
<p>Before our class will be able to do much of anything, we <strong>need to connect to  our database.</strong> To do this, we&#8217;ll need to create a couple of small files.</p>
<h4>Defining Site-Wide Constants</h4>
<p>Our site won&#8217;t require many <a href="http://php.net/constants">constants</a>, but in the interest of keeping them  easy to maintain, we&#8217;ll <strong>create a separate file to contain any information that  is site-wide.</strong> This will be called <tt>constants.inc.php</tt>, and it will reside in a  new folder called <tt>inc</tt> &mdash; this folder will contain our PHP classes as well.</p>
<p>Creating a constants file is a good idea for pieces of <strong>information that will  be used often and in different scopes throughout a site.</strong> That way, if your  database changes, you&#8217;re able to change every database connection <em>simply by  swapping out the information in one file. </em></p>
<p>Inside <tt>constants.inc.php</tt>, we want to <strong>define our database credentials.</strong> Since we&#8217;re starting out by developing locally, <tt>constants.inc.php</tt> will look  like this:</p>
<pre class="brush: php">&lt;?php

    // Database credentials
    define('DB_HOST', 'localhost');
    define('DB_USER', 'root');
    define('DB_PASS', '');
    define('DB_NAME', 'cl_db');

?&gt;</pre>
<p>As we develop, we&#8217;ll add more to this file.</p>
<h4>Creating a PDO Object</h4>
<p>Next, we want to <strong>create a connection so that our application can communicate  with our database. </strong>This file will reside in the <tt>common</tt> folder along with the  header, footer, and sidebar files. This file will create a database connection  using <a href="http://php.net/pdo">PDO (PHP Data Objects)</a>, as well as setting up a couple other site-wide  features: <strong>error reporting and opening a session.</strong></p>
<p>The file will look like this when all&#8217;s said and done:</p>
<pre class="brush: php">&lt;?php
    // Set the error reporting level
    error_reporting(E_ALL);
    ini_set("display_errors", 1);

    // Start a PHP session
    session_start();

    // Include site constants
    include_once "inc/constants.inc.php";

    // Create a database object
    try {
        $dsn = "mysql:host=".DB_HOST.";dbname=".DB_NAME;
        $db = new PDO($dsn, DB_USER, DB_PASS);
    } catch (PDOException $e) {
        echo 'Connection failed: ' . $e-&gt;getMessage();
        exit;
    }
?&gt;</pre>
<p>Because we&#8217;re in the development stage, we want to <strong>see any and every error  that occurs on the site. </strong>By setting <a href="http://us.php.net/manual/en/function.error-reporting.php"><tt>error_reporting()</tt></a> to <tt>E_ALL</tt> and changing  the <a href="http://us.php.net/manual/en/errorfunc.configuration.php#ini.display-errors"><tt>display_errors</tt></a> directive to <tt>1</tt> using <a href="http://php.net/ini_set"><tt>ini_set()</tt></a>, we ensure that even notices  will be displayed, which will keep our code cleaner and more secure.</p>
<p>Next, we use <a href="http://php.net/session_start"><tt>session_start()</tt></a> to start a PHP session. This will <strong>allow our users  to stay logged in </strong>when we build that functionality later.</p>
<p>Finally, we<strong> include <tt>config.inc.php</tt> and create a PDO object using the constants  defined within it.</strong> Note the use of the <tt>try-catch</tt> statement&mdash;this gives us the  ability to use <a href="http://us2.php.net/manual/en/language.exceptions.php">Exceptions</a>, which help improve error handling. In this case, if  the database connection fails, we&#8217;re simply going to output the error message.</p>
<h4>Why PDO?</h4>
<p>The reason we&#8217;re using PDO for this project is because of its <strong>support for <a href="http://us.php.net/manual/en/pdo.prepared-statements.php"> prepared statements</a>,</strong> which virtually eliminates the risk of <a href="http://en.wikipedia.org/wiki/SQL_injection">SQL injection</a>.  There are other options that allow prepared statements, such as the <a href="http://php.net/mysqli">MySQLi  extension</a>. However, <em>PDO is not database-specific,</em> so migrating the app to  Oracle or PostgreSQL wouldn&#8217;t require a full rewrite of our code.</p>
<p>Also, having used both MySQLi and PDO in projects, it&#8217;s just my personal  preference to use PDO. Feel free to use whatever method of connecting to the  database you prefer, but <em>keep in mind that all database interactions in this  exercise are assuming the use of PDO,</em> and as such will probably require some  reworking to accommodate your changes.</p>
<h4>Framing Out a User Interactions Class</h4>
<p>As we discussed in <a href="/blog/creating-an-app-from-scratch-part-2/">Part 2</a> of this series, <strong>we&#8217;ll be taking the  <a href="/blog/ITT %2310%3A Understanding OOP/">object-oriented approach</a> with this app.</strong> All of these actions will be contained  within our <tt>ColoredListsUsers</tt> class. We&#8217;ll also need to create several files  that will <strong>display information to the user and interact with the class,</strong> which  we&#8217;ll cover as we get to them.</p>
<h3>Building the Class</h3>
<p>To get started, we need to <strong>create the file</strong> <tt>class.users.inc.php</tt> to contain the  PHP class, which we&#8217;ll place in the <tt>inc</tt> folder.</p>
<p>With the file created, let&#8217;s build the skeleton of the class:</p>
<pre class="brush: php">&lt;?php

/**
 * Handles user interactions within the app
 *
 * PHP version 5
 *
 * @author Jason Lengstorf
 * @author Chris Coyier
 * @copyright 2009 Chris Coyier and Jason Lengstorf
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 *
 */
class ColoredListsUsers
{



}


?&gt;</pre>
<h4>Connecting the Class to the Database</h4>
<p>Before our class can do much of anything, <strong>it needs to have access to the  database object</strong> we created in <tt>base.php</tt>. Our database connection within the  object will be stored in a private property called <tt>$_db</tt>, and this property  will be set by the class <a href="http://us2.php.net/manual/en/language.oop5.decon.php">constructor</a>, which will accept the instance of PDO  created in <tt>base.php</tt> as an argument. <em>If no instance of PDO is passed, one will  be created by the constructor.</em></p>
<p>This ends up looking like this:</p>
<pre class="brush: php">class ColoredListsUsers
{
    /**
     * The database object
     *
     * @var object
     */
    private $_db;

    /**
     * Checks for a database object and creates one if none is found
     *
     * @param object $db
     * @return void
     */
    public function __construct($db=NULL)
    {
        if(is_object($db))
        {
            $this-&gt;_db = $db;
        }
        else
        {
            $dsn = "mysql:host=".DB_HOST.";dbname=".DB_NAME;
            $this-&gt;_db = new PDO($dsn, DB_USER, DB_PASS);
        }
    }
}</pre>
<p>Now we are able to create an instance of our <tt>ColoredListsUsers</tt> object and use  it to communicate with our database. Next, let&#8217;s start building user  interactions!</p>
<h3>Creating an Account</h3>
<p>First and foremost, <strong>a user needs to be able to create an account.</strong> This will  give them access to the rest of the site&#8217;s functionality.</p>
<p>As it stands, when a user visits our app, they&#8217;re greeted with our &#8220;sales&#8221;  page, which encourages them to click the &#8220;Sign Up&#8221; button in the top right of  their screen:</p>
<div class="main_image"><img src="/assets/images/app-from-scratch/05-01.png" alt="App home screen" /> <span class="imagetext">The home screen of our app</span></div>
<p>Clicking that &#8220;Sign Up&#8221; button directs the user to <tt>/signup.php</tt>&mdash;our first  order of business should probably be to build that page.</p>
<h4>Creating the Sign-Up Form</h4>
<p>In our app&#8217;s root directory, create a file called <tt>signup.php</tt> and place the  following code inside:</p>
<pre class="brush: php">&lt;?php
    include_once "common/base.php";
    $pageTitle = "Register";
    include_once "common/header.php";

    if(!empty($_POST['username'])):
        include_once "inc/class.users.inc.php";
        $users = new ColoredListsUsers($db);
        echo $users-&gt;createAccount();
    else:
?&gt;

        &lt;h2&gt;Sign up&lt;/h2&gt;
        &lt;form method="post" action="signup.php" id="registerform"&gt;
            &lt;div&gt;
                &lt;label for="username"&gt;Email:&lt;/label&gt;
                &lt;input type="text" name="username" id="username" /&gt;&lt;br /&gt;
                &lt;input type="submit" name="register" id="register" value="Sign up" /&gt;
            &lt;/div&gt;
        &lt;/form&gt;

&lt;?php
    endif;
    include_once 'common/close.php';
?&gt;</pre>
<p>To start, we include our <tt>common/base.php</tt> and <tt>common/header.php</tt> files. Also,  notice that we&#8217;re declaring a variable called <tt>$pageTitle</tt> just before we  include the header. Remember in <a href="http://css-tricks.com/app-from-scratch-4-html-css">Part 4</a> when we built the header file and left  that comment in the title tag?</p>
<pre class="brush: php">&lt;title&gt;Colored Lists | &lt;!-- Do Something Smart Here --&gt;&lt;/title&gt;</pre>
<p>We&#8217;re going to replace that with a snippet of PHP that reads:</p>
<pre class="brush: php">&lt;title&gt;Colored Lists | &lt;?php echo $pageTitle ?&gt;&lt;/title&gt;</pre>
<p>That gives us the opportunity to post a different title for each page of our  app.</p>
<p>With the proper files included, we can then <strong>create our sign-up form.</strong> The form  will submit to <tt>signup.php</tt>&mdash;itself&mdash;so we need to place an <tt>if-else</tt> check to see  if the form has been submitted. If so, we create a new <tt>ColoredListsUsers</tt> object and call the <tt>createAccount()</tt> method (which we&#8217;ll write in the next  section).</p>
<p>Finally, we close the <tt>if-else</tt> statement and include the footer. Our sign-up  page should look like this:</p>
<div class="main_image"><img src="/assets/images/app-from-scratch/05-02.png" alt="The sign-up page" /> <span class="imagetext">The sign-up page.</span></div>
<p><strong>Notice the use of alternative syntax for the <tt>if-else</tt> statement.</strong> Normally, I  don&#8217;t like to use this format, but in the case of outputting HTML, I prefer  the way it ends with <tt>endif;</tt> instead of a closing curly brace (<tt>}</tt>), which helps  with readability in the script.</p>
<h4>Saving the User&#8217;s Email Address</h4>
<p>With our sign-up form ready, we need to write the <tt>createAccount()</tt> method that  will be called when a user submits the form. This method will be public. Let&#8217;s  go back to <tt>inc/class.users.inc.php</tt> and declare this method:</p>
<pre class="brush: php">class ColoredListsUsers
{
    // Class properties and other methods omitted to save space

    /**
     * Checks and inserts a new account email into the database
     *
     * @return string    a message indicating the action status
     */
    public function createAccount()
    {
        $u = trim($_POST['username']);
        $v = sha1(time());

        $sql = "SELECT COUNT(Username) AS theCount
                FROM users
                WHERE Username=:email";
        if($stmt = $this-&gt;_db-&gt;prepare($sql)) {
            $stmt-&gt;bindParam(":email", $u, PDO::PARAM_STR);
            $stmt-&gt;execute();
            $row = $stmt-&gt;fetch();
            if($row['theCount']!=0) {
                return "&lt;h2&gt; Error &lt;/h2&gt;"
                    . "&lt;p&gt; Sorry, that email is already in use. "
                    . "Please try again. &lt;/p&gt;";
            }
            if(!$this-&gt;sendVerificationEmail($u, $v)) {
                return "&lt;h2&gt; Error &lt;/h2&gt;"
                    . "&lt;p&gt; There was an error sending your"
                    . " verification email. Please "
                    . "&lt;a href="mailto:help@coloredlists.com"&gt;contact "
                    . "us&lt;/a&gt; for support. We apologize for the "
                    . "inconvenience. &lt;/p&gt;";
            }
            $stmt-&gt;closeCursor();
        }

        $sql = "INSERT INTO users(Username, ver_code)
                VALUES(:email, :ver)";
        if($stmt = $this-&gt;_db-&gt;prepare($sql)) {
            $stmt-&gt;bindParam(":email", $u, PDO::PARAM_STR);
            $stmt-&gt;bindParam(":ver", $v, PDO::PARAM_STR);
            $stmt-&gt;execute();
            $stmt-&gt;closeCursor();

            $userID = $this-&gt;_db-&gt;lastInsertId();
            $url = dechex($userID);

            /*
             * If the UserID was successfully
             * retrieved, create a default list.
             */
            $sql = "INSERT INTO lists (UserID, ListURL)
                    VALUES ($userID, $url)";
            if(!$this-&gt;_db-&gt;query($sql)) {
                return "&lt;h2&gt; Error &lt;/h2&gt;"
                    . "&lt;p&gt; Your account was created, but "
                    . "creating your first list failed. &lt;/p&gt;";
            } else {
                return "&lt;h2&gt; Success! &lt;/h2&gt;"
                    . "&lt;p&gt; Your account was successfully "
                    . "created with the username &lt;strong&gt;$u&lt;/strong&gt;."
                    . " Check your email!";
            }
        } else {
            return "&lt;h2&gt; Error &lt;/h2&gt;&lt;p&gt; Couldn't insert the "
                . "user information into the database. &lt;/p&gt;";
        }
    }
}</pre>
<p>This method follows several steps to create an account: first, it <strong>retrieves  the posted email address from the form</strong> (stored in the <a href="http://us2.php.net/manual/en/reserved.variables.post.php"><tt>$_POST</tt> superglobal</a>) and  generates a hard-to-guess verification code (the SHA1 hash of the current  timestamp); second, it <strong>makes sure the supplied email address isn&#8217;t already in  use;</strong> third, <strong>it generates and sends a verification email to the user</strong> with  instructions on how to verify their account (we&#8217;ll define the method that does  this in the next section); fourth, <strong>it stores the email address and verification code in the database;</strong> and finally, <strong>it creates a list for the user.</strong></p>
<p>Each of these steps is monitored, and if any of them should fail, a specific  error message is generated. Upon success, a message is generated to let the  user know they should expect an email.</p>
<h4>Generating and Sending a Verification Email</h4>
<p>When the user creates an account, we need to <strong>send them an email with a link  that will confirm their account.</strong> This is a precautionary measure that proves  the user provided a real email address that they have access to and prevents a  ton of spam accounts from being created easily.</p>
<p>To send the email, we&#8217;ll be using the built-in <a href="http://php.net/mail"><tt>mail()</tt></a> function. In  <tt>inc/class.users.inc.php</tt>, create the private <tt>sendVerificationEmail()</tt> method by  inserting the following code:</p>
<pre class="brush: php">class ColoredListsUsers
{
    // Class properties and other methods omitted to save space

    /**
     * Sends an email to a user with a link to verify their new account
     *
     * @param string $email    The user's email address
     * @param string $ver    The random verification code for the user
     * @return boolean        TRUE on successful send and FALSE on failure
     */
    private function sendVerificationEmail($email, $ver)
    {
        $e = sha1($email); // For verification purposes
        $to = trim($email);

        $subject = "[Colored Lists] Please Verify Your Account";

        $headers = &lt;&lt;&lt;MESSAGE
From: Colored Lists &lt;donotreply@coloredlists.com&gt;
Content-Type: text/plain;
MESSAGE;

        $msg = &lt;&lt;&lt;EMAIL
You have a new account at Colored Lists!

To get started, please activate your account and choose a
password by following the link below.

Your Username: $email

Activate your account: http://coloredlists.com/accountverify.php?v=$ver&amp;e=$e

If you have any questions, please contact help@coloredlists.com.

--
Thanks!

Chris and Jason
www.ColoredLists.com
EMAIL;

        return mail($to, $subject, $msg, $headers);
    }
}</pre>
<p>The most important part of this method is the activation link,  <tt>http://coloredlists.com/accountverify.php?v=$ver&amp;e=$e</tt>. This link<strong> sends the  user to our app&#8217;s account verification file </strong>(which we&#8217;ll write in the next  step) <strong>and sends the user&#8217;s hashed email address along with their verification  code in the URI.</strong> This will allow us to identify and verify the user when they  follow the link.</p>
<h4>Verifying the User&#8217;s Account</h4>
<p>After our user follows the verification link in the email, we need to <strong>check  that their email and verification code are valid, and then allow them to  choose a password.</strong> After they choose a password, we need to <strong>update the  database to reflect the user&#8217;s new password, as well as setting the account&#8217;s  status to verified.</strong></p>
<p>First, let&#8217;s create a new file called <tt>accountverify.php</tt> in the root level of  our app. Inside, place the following code:</p>
<pre class="brush: php">&lt;?php
    include_once "common/base.php";
    $pageTitle = "Verify Your Account";
    include_once "common/header.php";

    if(isset($_GET['v']) &amp;&amp; isset($_GET['e']))
    {
        include_once "inc/class.users.inc.php";
        $users = new ColoredListsUsers($db);
        $ret = $users-&gt;verifyAccount();
    }
    elseif(isset($_POST['v']))
    {
        include_once "inc/class.users.inc.php";
        $users = new ColoredListsUsers($db);
        $ret = $users-&gt;updatePassword();
    }
    else
    {
        header("Location: /signup.php");
        exit;
    }

    if(isset($ret[0])):
        echo isset($ret[1]) ? $ret[1] : NULL;

        if($ret[0]&lt;3):
?&gt;

        &lt;h2&gt;Choose a Password&lt;/h2&gt;

        &lt;form method="post" action="accountverify.php"&gt;
            &lt;div&gt;
                &lt;label for="p"&gt;Choose a Password:&lt;/label&gt;
                &lt;input type="password" name="p" id="p" /&gt;&lt;br /&gt;
                &lt;label for="r"&gt;Re-Type Password:&lt;/label&gt;
                &lt;input type="password" name="r" id="r" /&gt;&lt;br /&gt;
                &lt;input type="hidden" name="v" value="&lt;?php echo $_GET['v'] ?&gt;" /&gt;
                &lt;input type="submit" name="verify" id="verify" value="Verify Your Account" /&gt;
            &lt;/div&gt;
        &lt;/form&gt;

&lt;?php
        endif;
    else:
        echo '&lt;meta http-equiv="refresh" content="0;/"&gt;';
    endif;

    include_once("common/ads.php");
    include_once 'common/close.php';
?&gt;</pre>
<h4>Verifying the User&#8217;s Email and Verification Code</h4>
<p>Before we can allow our user to select a password, we need to <strong>make sure that  their account exists, that their email matches their verification code, and  that their account is unverified.</strong> To do that, we need a new method in  <tt>inc/class.users.inc.php</tt> called <tt>verifyAccount()</tt>:</p>
<pre class="brush: php">class ColoredListsUsers
{
    // Class properties and other methods omitted to save space

    /**
     * Checks credentials and verifies a user account
     *
     * @return array    an array containing a status code and status message
     */
    public function verifyAccount()
    {
        $sql = "SELECT Username
                FROM users
                WHERE ver_code=:ver
                AND SHA1(Username)=:user
                AND verified=0";

        if($stmt = $this-&gt;_db-&gt;prepare($sql))
        {
            $stmt-&gt;bindParam(':ver', $_GET['v'], PDO::PARAM_STR);
            $stmt-&gt;bindParam(':user', $_GET['e'], PDO::PARAM_STR);
            $stmt-&gt;execute();
            $row = $stmt-&gt;fetch();
            if(isset($row['Username']))
            {
                // Logs the user in if verification is successful
                $_SESSION['Username'] = $row['Username'];
                $_SESSION['LoggedIn'] = 1;
            }
            else
            {
                return array(4, "&lt;h2&gt;Verification Error&lt;/h2&gt;n"
                    . "&lt;p&gt;This account has already been verified. "
                    . "Did you &lt;a href="/password.php"&gt;forget "
                    . "your password?&lt;/a&gt;");
            }
            $stmt-&gt;closeCursor();

            // No error message is required if verification is successful
            return array(0, NULL);
        }
        else
        {
            return array(2, "&lt;h2&gt;Error&lt;/h2&gt;n&lt;p&gt;Database error.&lt;/p&gt;");
        }
    }
}</pre>
<p>This method executes a query that loads the user name stored in the database  with the verification code, hashed user name, and a verified status of <tt>0</tt>. If a  user name is returned, login credentials are stored. <strong>This method returns an  array with an error code in the first index, and a message in the second.</strong> The  error code <tt>0</tt> means nothing went wrong.</p>
<h4>Updating the User&#8217;s Password and Verified Status</h4>
<p>Once the user has selected a password and submitted the form, the <tt>if-else</tt> statement will catch the verification code sent using the <tt>POST</tt> method and  execute the <tt>updatePassword()</tt> method. This method needs to set the account  status to verified and save the user&#8217;s hashed password in the database. Let&#8217;s  build this method in <tt>ColoredListsUsers</tt>:</p>
<pre class="brush: php">class ColoredListsUsers
{
    // Class properties and other methods omitted to save space

    /**
     * Changes the user's password
     *
     * @return boolean    TRUE on success and FALSE on failure
     */
    public function updatePassword()
    {
        if(isset($_POST['p'])
        &amp;&amp; isset($_POST['r'])
        &amp;&amp; $_POST['p']==$_POST['r'])
        {
            $sql = "UPDATE users
                    SET Password=MD5(:pass), verified=1
                    WHERE ver_code=:ver
                    LIMIT 1";
            try
            {
                $stmt = $this-&gt;_db-&gt;prepare($sql);
                $stmt-&gt;bindParam(":pass", $_POST['p'], PDO::PARAM_STR);
                $stmt-&gt;bindParam(":ver", $_POST['v'], PDO::PARAM_STR);
                $stmt-&gt;execute();
                $stmt-&gt;closeCursor();

                return TRUE;
            }
            catch(PDOException $e)
            {
                return FALSE;
            }
        }
        else
        {
            return FALSE;
        }
    }
}</pre>
<p>Finally, since verifying an account logs a user in, we need to update  <tt>common/header.php</tt> to <strong>recognize that a user is logged in and display different  options.</strong> In <a href="http://css-tricks.com/app-from-scratch-4-html-css">Part 4</a>, <tt>common/header.php</tt> featured a code snippet that looked like  this:</p>
<pre class="brush: php">&lt;!-- IF LOGGED IN --&gt;
                &lt;p&gt;&lt;a href="/logout.php" class="button"&gt;Log out&lt;/a&gt; &lt;a href="/account.php" class="button"&gt;Your Account&lt;/a&gt;&lt;/p&gt;

&lt;!-- IF LOGGED OUT --&gt;
                &lt;p&gt;&lt;a class="button" href="/signup.php"&gt;Sign up&lt;/a&gt; &amp;nbsp; &lt;a class="button" href="/login.php"&gt;Log in&lt;/a&gt;&lt;/p&gt;
&lt;!-- END OF IF STATEMENT --&gt;</pre>
<p>To make those comments into functional code, we need to modify this snippet  with an <tt>if-else</tt> block:</p>
<pre class="brush: php">&lt;?php
    if(isset($_SESSION['LoggedIn']) &amp;&amp; isset($_SESSION['Username'])
        &amp;&amp; $_SESSION['LoggedIn']==1):
?&gt;
                &lt;p&gt;&lt;a href="/logout.php" class="button"&gt;Log out&lt;/a&gt; &lt;a href="/account.php" class="button"&gt;Your Account&lt;/a&gt;&lt;/p&gt;
&lt;?php else: ?&gt;
                &lt;p&gt;&lt;a class="button" href="/signup.php"&gt;Sign up&lt;/a&gt; &amp;nbsp; &lt;a class="button" href="/login.php"&gt;Log in&lt;/a&gt;&lt;/p&gt;
&lt;?php endif; ?&gt;</pre>
<p>Notice that we store in the session both the user name (<tt>$_SESSION['Username']</tt>)  and a flag that tells us if the user is logged in (<tt>$_SESSION['LoggedIn']</tt>).</p>
<h4>Logging In</h4>
<p>Next, let&#8217;s <strong>build the login form and allow our user to log in.</strong> To start, let&#8217;s  create a new file named <tt>login.php</tt> at the root level of our app. Like our other  publicly displayed files, this will include the base and header files. Then it  checks if a user is already logged in, if the login form was submitted, or if  the user needs to log in.</p>
<p>If logged in, the user is notified of this fact and asked if he or she wishes  to log out.</p>
<p>If the form has been submitted, a new <tt>ColoredListsUsers</tt> object is created and  the <tt>accountLogin()</tt> method is called. If the login succeeds, the user is  directed to the home page, where his or her list will appear; otherwise, the  login form is displayed again with an error.</p>
<p>If neither of the previous conditions exists, the login form is displayed.</p>
<p>Finally, the sidebar ads and footer are included to round out the file.</p>
<p>When the file is all put together, it should look like this:</p>
<pre class="brush: php">&lt;?php
    include_once "common/base.php";
    $pageTitle = "Home";
    include_once "common/header.php";

    if(!empty($_SESSION['LoggedIn']) &amp;&amp; !empty($_SESSION['Username'])):
?&gt;

        &lt;p&gt;You are currently &lt;strong&gt;logged in.&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;&lt;a href="/logout.php"&gt;Log out&lt;/a&gt;&lt;/p&gt;
&lt;?php
    elseif(!empty($_POST['username']) &amp;&amp; !empty($_POST['password'])):
        include_once 'inc/class.users.inc.php';
        $users = new ColoredListsUsers($db);
        if($users-&gt;accountLogin()===TRUE):
            echo "&lt;meta http-equiv='refresh' content='0;/'&gt;";
            exit;
        else:
?&gt;

        &lt;h2&gt;Login Failed&amp;mdash;Try Again?&lt;/h2&gt;
        &lt;form method="post" action="login.php" name="loginform" id="loginform"&gt;
            &lt;div&gt;
                &lt;input type="text" name="username" id="username" /&gt;
                &lt;label for="username"&gt;Email&lt;/label&gt;
                &lt;br /&gt;&lt;br /&gt;
                &lt;input type="password" name="password" id="password" /&gt;
                &lt;label for="password"&gt;Password&lt;/label&gt;
                &lt;br /&gt;&lt;br /&gt;
                &lt;input type="submit" name="login" id="login" value="Login" class="button" /&gt;
            &lt;/div&gt;
        &lt;/form&gt;
        &lt;p&gt;&lt;a href="/password.php"&gt;Did you forget your password?&lt;/a&gt;&lt;/p&gt;
&lt;?php
        endif;
    else:
?&gt;

        &lt;h2&gt;Your list awaits...&lt;/h2&gt;
        &lt;form method="post" action="login.php" name="loginform" id="loginform"&gt;
            &lt;div&gt;
                &lt;input type="text" name="username" id="username" /&gt;
                &lt;label for="username"&gt;Email&lt;/label&gt;
                &lt;br /&gt;&lt;br /&gt;
                &lt;input type="password" name="password" id="password" /&gt;
                &lt;label for="password"&gt;Password&lt;/label&gt;
                &lt;br /&gt;&lt;br /&gt;
                &lt;input type="submit" name="login" id="login" value="Login" class="button" /&gt;
            &lt;/div&gt;
        &lt;/form&gt;&lt;br /&gt;&lt;br /&gt;
        &lt;p&gt;&lt;a href="/password.php"&gt;Did you forget your password?&lt;/a&gt;&lt;/p&gt;
&lt;?php
    endif;
?&gt;

        &lt;div style="clear: both;"&gt;&lt;/div&gt;
&lt;?php
    include_once "common/ads.php";
    include_once "common/close.php";
?&gt;</pre>
<p>Notice the &#8220;Did you forget your password?&#8221; links &mdash; we&#8217;ll be building this  functionality a little later on in the article.</p>
<h4>Building the Login Method</h4>
<p>Now we need to build the <tt>accountLogin()</tt> method. This method will <strong>compare the  supplied user name and the MD5 hash of the supplied password to verify that  there is a matching pair in the database.</strong> If a match is found, the user&#8217;s name  and a login flag are stored in the session and the method returns <tt>TRUE</tt>. If no match is found, the method returns <tt>FALSE</tt>.</p>
<p>Build this method in <tt>ColoredListsUsers</tt> by inserting the following code:</p>
<pre class="brush: php">class ColoredListsUsers
{
    // Class properties and other methods omitted to save space


    /**
     * Checks credentials and logs in the user
     *
     * @return boolean    TRUE on success and FALSE on failure
     */
    public function accountLogin()
    {
        $sql = "SELECT Username
                FROM users
                WHERE Username=:user
                AND Password=MD5(:pass)
                LIMIT 1";
        try
        {
            $stmt = $this-&gt;_db-&gt;prepare($sql);
            $stmt-&gt;bindParam(':user', $_POST['username'], PDO::PARAM_STR);
            $stmt-&gt;bindParam(':pass', $_POST['password'], PDO::PARAM_STR);
            $stmt-&gt;execute();
            if($stmt-&gt;rowCount()==1)
            {
                $_SESSION['Username'] = htmlentities($_POST['username'], ENT_QUOTES);
                $_SESSION['LoggedIn'] = 1;
                return TRUE;
            }
            else
            {
                return FALSE;
            }
        }
        catch(PDOException $e)
        {
            return FALSE;
        }
    }
}</pre>
<h4>Logging Out</h4>
<p>Next, our user needs to be able to log out. This is as easy as destroying the  login data stored in the session and sending the user back to the login page.</p>
<p>Create a new file named <tt>logout.php</tt> at the root level of the app and place the  following code inside:</p>
<pre class="brush: php">&lt;?php

    session_start();

    unset($_SESSION['LoggedIn']);
    unset($_SESSION['Username']);

?&gt;

&lt;meta http-equiv="refresh" content="0;login.php"&gt;</pre>
<h4>Modifying Account Information</h4>
<p>Next, we need to <strong>allow our users to modify their account information.</strong> In order  to do that, we need to provide an &#8220;Account&#8221; page that will give them options  to <strong>change their user name or password, as well as the option to delete their  account.</strong></p>
<p>Create a file named <tt>account.php</tt> at the root level of the app. There&#8217;s a lot  going on here because we&#8217;re essentially combining three app functions within  one file.</p>
<p>First, we <strong>include the base file and check that the user is logged in.</strong> If not,  he or she gets sent out to the main page.</p>
<p>If the user is logged in, we <strong>check if any actions have already been attempted</strong> and assemble the corresponding success or failure messages if any are found.</p>
<p>Then we <strong>load the user&#8217;s ID and verification code</strong> using the method  <tt>retrieveAccountInfo()</tt> and build three forms: one to update the user name  (which is an email address, remember), one to change the account password, and  one to delete the account.</p>
<p>Finally, we include the sidebar ads and the footer. Altogether, the file  should look like this:</p>
<pre class="brush: php">&lt;?php
    include_once "common/base.php";
    if(isset($_SESSION['LoggedIn']) &amp;&amp; $_SESSION['LoggedIn']==1):
        $pageTitle = "Your Account";
        include_once "common/header.php";
        include_once 'inc/class.users.inc.php';
        $users = new ColoredListsUsers($db);

        if(isset($_GET['email']) &amp;&amp; $_GET['email']=="changed")
        {
            echo "&lt;div class='message good'&gt;Your email address "
                . "has been changed.&lt;/div&gt;";
        }
        else if(isset($_GET['email']) &amp;&amp; $_GET['email']=="failed")
        {
            echo "&lt;div class='message bad'&gt;There was an error "
                . "changing your email address.&lt;/div&gt;";
        }

        if(isset($_GET['password']) &amp;&amp; $_GET['password']=="changed")
        {
            echo "&lt;div class='message good'&gt;Your password "
                . "has been changed.&lt;/div&gt;";
        }
        elseif(isset($_GET['password']) &amp;&amp; $_GET['password']=="nomatch")
        {
            echo "&lt;div class='message bad'&gt;The two passwords "
                . "did not match. Try again!&lt;/div&gt;";
        }

        if(isset($_GET['delete']) &amp;&amp; $_GET['delete']=="failed")
        {
            echo "&lt;div class='message bad'&gt;There was an error "
                . "deleting your account.&lt;/div&gt;";
        }

        list($userID, $v) = $users-&gt;retrieveAccountInfo();
?&gt;

        &lt;h2&gt;Your Account&lt;/h2&gt;
        &lt;form method="post" action="db-interaction/users.php"&gt;
            &lt;div&gt;
                &lt;input type="hidden" name="userid"
                    value="&lt;?php echo $userID ?&gt;" /&gt;
                &lt;input type="hidden" name="action"
                    value="changeemail" /&gt;
                &lt;input type="text" name="username" id="username" /&gt;
                &lt;label for="username"&gt;Change Email Address&lt;/label&gt;
                &lt;br /&gt;&lt;br /&gt;
                &lt;input type="submit" name="change-email-submit"
                    id="change-email-submit" value="Change Email"
                    class="button" /&gt;
            &lt;/div&gt;
        &lt;/form&gt;&lt;br /&gt;&lt;br /&gt;

        &lt;form method="post" action="db-interaction/users.php"
            id="change-password-form"&gt;
            &lt;div&gt;
                &lt;input type="hidden" name="user-id"
                    value="&lt;?php echo $userID ?&gt;" /&gt;
                &lt;input type="hidden" name="v"
                    value="&lt;?php echo $v ?&gt;" /&gt;
                &lt;input type="hidden" name="action"
                    value="changepassword" /&gt;
                &lt;input type="password"
                    name="p" id="new-password" /&gt;
                &lt;label for="password"&gt;New Password&lt;/label&gt;
                &lt;br /&gt;&lt;br /&gt;
                &lt;input type="password" name="r"
                    id="repeat-new-password" /&gt;
                &lt;label for="password"&gt;Repeat New Password&lt;/label&gt;
                &lt;br /&gt;&lt;br /&gt;
                &lt;input type="submit" name="change-password-submit"
                    id="change-password-submit" value="Change Password"
                    class="button" /&gt;
            &lt;/div&gt;
        &lt;/form&gt;
        &lt;hr /&gt;

        &lt;form method="post" action="deleteaccount.php"
            id="delete-account-form"&gt;
            &lt;div&gt;
                &lt;input type="hidden" name="user-id"
                    value="&lt;?php echo $userID ?&gt;" /&gt;
                &lt;input type="submit"
                    name="delete-account-submit" id="delete-account-submit"
                    value="Delete Account?" class="button" /&gt;
            &lt;/div&gt;
        &lt;/form&gt;

&lt;?php
    else:
        header("Location: /");
        exit;
    endif;
?&gt;

&lt;div class="clear"&gt;&lt;/div&gt;

&lt;?php
    include_once "common/ads.php";
    include_once "common/close.php";
?&gt;</pre>
<h4>Creating the Method to Retrieve Account Info</h4>
<p>In order to have the user&#8217;s login name and verification code available to our  account option forms, we need to build a new method that will load this  information from the database. In <tt>inc/class.users.inc.php</tt>, create a new method  in <tt>ColoredListsUsers</tt> called <tt>retrieveAccountInfo()</tt> and add the following code:</p>
<pre class="brush: php">class ColoredListsUsers
{
    // Class properties and other methods omitted to save space


    /**
     * Retrieves the ID and verification code for a user
     *
     * @return mixed    an array of info or FALSE on failure
     */
    public function retrieveAccountInfo()
    {
        $sql = "SELECT UserID, ver_code
                FROM users
                WHERE Username=:user";
        try
        {
            $stmt = $this-&gt;_db-&gt;prepare($sql);
            $stmt-&gt;bindParam(':user', $_SESSION['Username'], PDO::PARAM_STR);
            $stmt-&gt;execute();
            $row = $stmt-&gt;fetch();
            $stmt-&gt;closeCursor();
            return array($row['UserID'], $row['ver_code']);
        }
        catch(PDOException $e)
        {
            return FALSE;
        }
    }
}</pre>
<h3>Building the Interactions File</h3>
<p>In <tt>account.php</tt>, all three forms direct to a file called  <tt>db-interaction/users.php</tt> when submitted. This file helps relieve some of the  clutter in <tt>account.php</tt> by determining form actions, creating a  <tt>ColoredListsUsers</tt> object, and calling the appropriate methods to handle the  action.</p>
<p>This file will be placed in a new folder called <tt>db-interaction</tt>, and it will be  named <tt>users.php</tt>. Place the following code in the new file:</p>
<pre class="brush: php">&lt;?php

session_start();

include_once "../inc/constants.inc.php";
include_once "../inc/class.users.inc.php";
$userObj = new ColoredListsUsers();

if(!empty($_POST['action'])
&amp;&amp; isset($_SESSION['LoggedIn'])
&amp;&amp; $_SESSION['LoggedIn']==1)
{
    switch($_POST['action'])
    {
        case 'changeemail':
            $status = $userObj-&gt;updateEmail() ? "changed" : "failed";
            header("Location: /account.php?email=$status");
            break;
        case 'changepassword':
            $status = $userObj-&gt;updatePassword() ? "changed" : "nomatch";
            header("Location: /account.php?password=$status");
            break;
        case 'deleteaccount':
            $userObj-&gt;deleteAccount();
            break;
        default:
            header("Location: /");
            break;
    }
}
elseif($_POST['action']=="resetpassword")
{
    if($resp=$userObj-&gt;resetPassword()===TRUE)
    {
        header("Location: /resetpending.php");
    }
    else
    {
        echo $resp;
    }
    exit;
}
else
{
    header("Location: /");
    exit;
}

?&gt;</pre>
<h3>Updating the Email Address</h3>
<p>When a user submits a request to change their email address, the method  <tt>updateEmail()</tt> is called. This function simply executes a query that changes  the email address associated with an account. It returns <tt>TRUE</tt> if the email is  successfully changed, and <tt>FALSE</tt> otherwise.</p>
<pre class="brush: php">class ColoredListsUsers
{
    // Class properties and other methods omitted to save space


    /**
     * Changes a user's email address
     *
     * @return boolean    TRUE on success and FALSE on failure
     */
    public function updateEmail()
    {
        $sql = "UPDATE users
                SET Username=:email
                WHERE UserID=:user
                LIMIT 1";
        try
        {
            $stmt = $this-&gt;_db-&gt;prepare($sql);
            $stmt-&gt;bindParam(':email', $_POST['username'], PDO::PARAM_STR);
            $stmt-&gt;bindParam(':user', $_POST['userid'], PDO::PARAM_INT);
            $stmt-&gt;execute();
            $stmt-&gt;closeCursor();

            // Updates the session variable
            $_SESSION['Username'] = htmlentities($_POST['username'], ENT_QUOTES);

            return TRUE;
        }
        catch(PDOException $e)
        {
            return FALSE;
        }
    }
}</pre>
<h3>Updating the Password</h3>
<p>Quite similarly to <tt>updateEmail()</tt>, <tt>updatePassword()</tt> is called if the user  submits a request to change their password. The only difference in the methods  is that this one will <strong>compare the password and the password confirmation to  make sure they match before saving.</strong></p>
<pre class="brush: php">class ColoredListsUsers
{
    // Class properties and other methods omitted to save space


    /**
     * Changes the user's password
     *
     * @return boolean    TRUE on success and FALSE on failure
     */
    public function updatePassword()
    {
        if(isset($_POST['p'])
        &amp;&amp; isset($_POST['r'])
        &amp;&amp; $_POST['p']==$_POST['r'])
        {
            $sql = "UPDATE users
                    SET Password=MD5(:pass), verified=1
                    WHERE ver_code=:ver
                    LIMIT 1";
            try
            {
                $stmt = $this-&gt;_db-&gt;prepare($sql);
                $stmt-&gt;bindParam(":pass", $_POST['p'], PDO::PARAM_STR);
                $stmt-&gt;bindParam(":ver", $_POST['v'], PDO::PARAM_STR);
                $stmt-&gt;execute();
                $stmt-&gt;closeCursor();

                return TRUE;
            }
            catch(PDOException $e)
            {
                return FALSE;
            }
        }
        else
        {
            return FALSE;
        }
    }
}</pre>
<h3>Deleting the Account</h3>
<p>If the user wants to delete their account, we need to go through several  steps. First, we need to <strong>double-check that the user is logged in,</strong> because we  certainly don&#8217;t want any accidental account deletions. If the user is logged  in, we then <strong>delete their list items.</strong> If the list items are successfully  deleted, we move on to <strong>delete the user&#8217;s lists.</strong> Finally, if the lists are  successfully deleted, we <strong>delete the user from the database, destroy their  session information, and send them to a page called <tt>gone.php</tt>,</strong> which we&#8217;ll  build in a minute.</p>
<p>The method, when it&#8217;s all written, will look like this:</p>
<pre class="brush: php">class ColoredListsUsers
{
    // Class properties and other methods omitted to save space


    /**
     * Deletes an account and all associated lists and items
     *
     * @return void
     */
    public function deleteAccount()
    {
        if(isset($_SESSION['LoggedIn']) &amp;&amp; $_SESSION['LoggedIn']==1)
        {
            // Delete list items
            $sql = "DELETE FROM list_items
                    WHERE ListID=(
                        SELECT ListID
                        FROM lists
                        WHERE UserID=:user
                        LIMIT 1
                    )";
            try
            {
                $stmt = $this-&gt;_db-&gt;prepare($sql);
                $stmt-&gt;bindParam(":user", $_POST['user-id'], PDO::PARAM_INT);
                $stmt-&gt;execute();
                $stmt-&gt;closeCursor();
            }
            catch(PDOException $e)
            {
                die($e-&gt;getMessage());
            }

            // Delete the user's list(s)
            $sql = "DELETE FROM lists
                    WHERE UserID=:user";
            try
            {
                $stmt = $this-&gt;_db-&gt;prepare($sql);
                $stmt-&gt;bindParam(":user", $_POST['user-id'], PDO::PARAM_INT);
                $stmt-&gt;execute();
                $stmt-&gt;closeCursor();
            }
            catch(PDOException $e)
            {
                die($e-&gt;getMessage());
            }

            // Delete the user
            $sql = "DELETE FROM users
                    WHERE UserID=:user
                    AND Username=:email";
            try
            {
                $stmt = $this-&gt;_db-&gt;prepare($sql);
                $stmt-&gt;bindParam(":user", $_POST['user-id'], PDO::PARAM_INT);
                $stmt-&gt;bindParam(":email", $_SESSION['Username'], PDO::PARAM_STR);
                $stmt-&gt;execute();
                $stmt-&gt;closeCursor();
            }
            catch(PDOException $e)
            {
                die($e-&gt;getMessage());
            }

            // Destroy the user's session and send to a confirmation page
            unset($_SESSION['LoggedIn'], $_SESSION['Username']);
            header("Location: /gone.php");
            exit;
        }
        else
        {
            header("Location: /account.php?delete=failed");
            exit;
        }
    }
}</pre>
<h3>Resetting an Account Password</h3>
<p>At this point, we&#8217;re almost done. The last thing we need to do is <strong>allow a user  to reset a forgotten password.</strong> To do this, we need to create the file  <tt>password.php</tt> at the root level of our app and place the following code inside:</p>
<pre class="brush: php">&lt;?php
    include_once "common/base.php";
    $pageTitle = "Reset Your Password";
    include_once "common/header.php";
?&gt;

        &lt;h2&gt;Reset Your Password&lt;/h2&gt;
        &lt;p&gt;Enter the email address you signed up with and we'll send
        you a link to reset your password.&lt;/p&gt;

        &lt;form action="db-interaction/users.php" method="post"&gt;
            &lt;div&gt;
                &lt;input type="hidden" name="action"
                    value="resetpassword" /&gt;
                &lt;input type="text" name="username" id="username" /&gt;
                &lt;label for="username"&gt;Email&lt;/label&gt;&lt;br /&gt;&lt;br /&gt;
                &lt;input type="submit" name="reset" id="reset"
                    value="Reset Password" class="button" /&gt;
            &lt;/div&gt;
        &lt;/form&gt;
&lt;?php
    include_once "common/ads.php";
    include_once "common/close.php";
?&gt;</pre>
<p>When a user visits this page, they&#8217;ll be able to enter their email address.  Submitting the form will <strong>return the account to unverified and send the user an  email with a link to reset their password.</strong></p>
<h4>Returning the Account to &#8220;Unverified&#8221; Status</h4>
<p>When the form in <tt>password.php</tt> is submitted, the information is sent to  <tt>db-interaction/users.php</tt> and the <tt>resetPassword()</tt> method is called before  sending the user to <tt>resetpending.php</tt>.</p>
<p>The <tt>resetPassword()</tt> method sets the verified field of our user&#8217;s database  entry to <tt>0</tt>, then calls the <tt>sendResetEmail()</tt> method.</p>
<pre class="brush: php">class ColoredListsUsers
{
    // Class properties and other methods omitted to save space


    /**
     * Resets a user's status to unverified and sends them an email
     *
     * @return mixed    TRUE on success and a message on failure
     */
    public function resetPassword()
    {
        $sql = "UPDATE users
                SET verified=0
                WHERE Username=:user
                LIMIT 1";
        try
        {
            $stmt = $this-&gt;_db-&gt;prepare($sql);
            $stmt-&gt;bindParam(":user", $_POST['username'], PDO::PARAM_STR);
            $stmt-&gt;execute();
            $stmt-&gt;closeCursor();
        }
        catch(PDOException $e)
        {
            return $e-&gt;getMessage();
        }

        // Send the reset email
        if(!$this-&gt;sendResetEmail($_POST['username'], $v))
        {
            return "Sending the email failed!";
        }
        return TRUE;
    }
}</pre>
<h4>Building the Reset Pending Page</h4>
<p>After the user&#8217;s account is back in an unverified state and the email has been  sent with their password reset link, we send them to <tt>resetpending.php</tt> to let  them know what their next steps are. Create this file at the root level of the  app and insert the following:</p>
<pre class="brush: php">&lt;?php
    include_once "common/base.php";
    $pageTitle = "Reset Pending";
    include_once "common/header.php";
?&gt;

        &lt;h2&gt;Password Reset Requested&lt;/h2&gt;
        &lt;p&gt;Check your email to finish the reset process.&lt;/p&gt;
&lt;?php
    include_once "common/ads.php";
    include_once "common/close.php";
?&gt;</pre>
<h4>Generating a &#8220;Reset Password&#8221; Email</h4>
<p>The <tt>sendResetEmail()</tt> method is very similar to the <tt>sendVerificationEmail()</tt> method. The main difference here is that the link sent to the user directs  them to a page called <tt>resetpassword.php</tt> where they&#8217;re able to choose a new  password.</p>
<pre class="brush: php">class ColoredListsUsers
{
    // Class properties and other methods omitted to save space


    /**
     * Sends a link to a user that lets them reset their password
     *
     * @param string $email    the user's email address
     * @param string $ver    the user's verification code
     * @return boolean        TRUE on success and FALSE on failure
     */
    private function sendResetEmail($email, $ver)
    {
        $e = sha1($email); // For verification purposes
        $to = trim($email);

        $subject = "[Colored Lists] Request to Reset Your Password";

        $headers = &lt;&lt;&lt;MESSAGE
From: Colored Lists &lt;donotreply@coloredlists.com&gt;
Content-Type: text/plain;
MESSAGE;

        $msg = &lt;&lt;&lt;EMAIL
We just heard you forgot your password! Bummer! To get going again,
head over to the link below and choose a new password.

Follow this link to reset your password:

http://coloredlists.com/resetpassword.php?v=$ver&#038;e=$e

If you have any questions, please contact help@coloredlists.com.

--
Thanks!

Chris and Jason
www.ColoredLists.com
EMAIL;

        return mail($to, $subject, $msg, $headers);
    }
}</pre>
<h4>Resetting the Password</h4>
<p>Our very last step in this part of the app is to create the file  <tt>resetpassword.php</tt> in the root level of the site. This file is very similar to  the <tt>accountverify.php</tt> file we created earlier. After including the base and  header files, it checks if the user is just arriving from their reset email.</p>
<p>If so, we are able to use the <tt>verifyAccount()</tt> method we wrote earlier to  ensure that their credentials are correct. After verifying their credentials,  we <strong>display a form that allows them to choose a password and confirm it.</strong></p>
<p>After submitting the form, our script will fire the <tt>updatePassword()</tt> method we  created earlier to <strong>save the new password.</strong> Then we redirect the user to  <tt>account.php</tt>, where they&#8217;re shown a confirmation message letting them know that  their password was changed.</p>
<p>Inside <tt>resetpassword.php</tt>, add the following code:</p>
<pre class="brush: php">&lt;?php
    include_once "common/base.php";

    if(isset($_GET['v']) &amp;&amp; isset($_GET['e']))
    {
        include_once "inc/class.users.inc.php";
        $users = new ColoredListsUsers($db);
        $ret = $users-&gt;verifyAccount();
    }
    elseif(isset($_POST['v']))
    {
        include_once "inc/class.users.inc.php";
        $users = new ColoredListsUsers($db);
        $status = $users-&gt;updatePassword() ? "changed" : "failed";
        header("Location: /account.php?password=$status");
        exit;
    }
    else
    {
        header("Location: /login.php");
        exit;
    }

    $pageTitle = "Reset Your Password";
    include_once "common/header.php";

    if(isset($ret[0])):
        echo isset($ret[1]) ? $ret[1] : NULL;

        if($ret[0]&lt;3):
?&gt;

        &lt;h2&gt;Reset Your Password&lt;/h2&gt;

        &lt;form method="post" action="accountverify.php"&gt;
            &lt;div&gt;
                &lt;label for="p"&gt;Choose a New Password:&lt;/label&gt;
                &lt;input type="password" name="p" id="p" /&gt;&lt;br /&gt;
                &lt;label for="r"&gt;Re-Type Password:&lt;/label&gt;
                &lt;input type="password" name="r" id="r" /&gt;&lt;br /&gt;
                &lt;input type="hidden" name="v" value="&lt;?php echo $_GET['v'] ?&gt;" /&gt;
                &lt;input type="submit" name="verify" id="verify" value="Reset Your Password" /&gt;
            &lt;/div&gt;
        &lt;/form&gt;

&lt;?php
        endif;
    else:
        echo '&lt;meta http-equiv="refresh" content="0;/"&gt;';
    endif;

    include_once("common/ads.php");
    include_once 'common/close.php';
?&gt;</pre>
<h3>Moving On&#8230;</h3>
<p>This article covered a whole lot of ground, and I went over some of it pretty  quickly. <strong>Please don&#8217;t hesitate to ask for clarification in the comments!</strong></p>
<p>In the next part of this series, our front-end designer will use some dummy  lists to create <a href="http://en.wikipedia.org/wiki/AJAX">AJAX</a> effects. After he&#8217;s finished with the dummy lists, we&#8217;ll  explore how to combine those AJAX effects with our back-end and build the list  interactions class in part 7.</p>
<div id="series-authors">
<h4>Series Authors</h4>
<div id="jason-series-author"><img style="margin: 0pt 10px 4px 0pt; float: left;" src="http://css-tricks.com/wp-content/csstricks-uploads/author-jason.jpg" alt="" width="125" height="125" /><strong>Jason Lengstorf</strong> is a software developer based in Missoula, MT. He is the author of <a href="http://www.amazon.com/gp/product/1430224738?ie=UTF8&amp;tag=ennudesi-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=1430224738">PHP for Absolute Beginners</a> and regularly blogs about programming. When not glued to his keyboard, he&rsquo;s likely standing in line for coffee, brewing his own beer, or daydreaming about being a Mythbuster.</div>
<div id="chris-series-author"><img style="margin: 0pt 0pt 4px 10px; float: right;" src="http://css-tricks.com/wp-content/csstricks-uploads/author-chris.jpg" alt="" width="125" height="125" /><strong>Chris Coyier</strong> is a designer currently living in Chicago, IL. He is the co-author of <a href="http://digwp.com/book/">Digging Into WordPress</a>, as well as blogger and speaker on all things design. Away from the computer, he is likely to be found yelling at Football coaches on TV or picking a banjo.</div>
</div>
<p>The post <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-5/">Creating an App from Scratch: Part 5</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-5/feed/</wfw:commentRss>
		<slash:comments>78</slash:comments>
		</item>
		<item>
		<title>Creating an App from Scratch: Part 3</title>
		<link>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-3/</link>
		<comments>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-3/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 06:01:14 +0000</pubDate>
		<dc:creator>Jason Lengstorf</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-3</guid>
		<description><![CDATA[<p>Part 3 of the Creating an App from Scratch series, in which Chris Coyier and Jason Lengstorf cover the workflow and design of the application. <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-3/" class="more-link">More</a></p><p>The post <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-3/">Creating an App from Scratch: Part 3</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<div id="series-header"><img src="/assets/images/app-from-scratch/03-header.jpg" alt="Creating a Web App from Scratch Part 3" /></div>
<div id="series-navigation">
<h5>All Series Navigation</h5>
<ul>
<li><a href="http://css-tricks.com/app-from-scratch-1-design">Part 1 &ndash; Planning the App: Basic Idea and Design</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-2/">Part 2 &ndash; Planning the App: Database Architecture and Development Approach</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-3/">Part 3 &#8211; Designing the App: Workflow Map and Photoshop Design</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-4-html-css">Part 4 &#8211; Designing the App: HTML and CSS</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-5/">Part 5 &#8211; Developing the App: User Interaction</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-6-ajax">Part 6 &#8211; Developing the App: Adding AJAX Interactivity</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-7/">Part 7 &#8211; Developing the App: List Interaction</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-8-finishing">Part 8 &ndash; Wrapping Up</a></li>
<li> And finally&#8230; the application! <a href="http://coloredlists.com">Colored Lists</a></li>
</ul>
</div>
<h3>Developing a Workflow</h3>
<p>We have a great start going on our list application at this point. The &#8220;big  idea&#8221; is in place, we know how we want the lists to be displayed and  interacted with, and we have some back-end structure in place to deal with  users and all the data that goes along with these lists.</p>
<p>It was a good idea to start with the &#8220;meat&#8221; of the app, but there is a little  bit more that goes into a full application. Because we have users, that means  we need a sign up form and a log in area for returning users. Because users  can be forgetful, <strong>we need a &#8216;Lost Password&#8217; feature.</strong> Because users should be  just as concerned about security as we are, <strong>users need to be able to change  their passwords, change their login, and delete their accounts.</strong> <em>Our one-page  app has just turned into a four or five page app, so we&#8217;re going to need to  think about some workflow.</em></p>
<p>There will be two different states for the homepage: <strong>logged in and logged out.</strong> While logged out, people need a way to sign in and to register, and this will  be essentially the &#8220;sales&#8221; page too, explaining the app. Logged in, the  homepage will be the user&#8217;s list itself. Logged in users will also need to do  some ancillary stuff related to their account, like change their email, change  their password, and delete their account, as well as a way to log out. These  ancillary options are probably best served on an account page. So now we are  looking at at least two new pages: Account Settings and Registration.  Here is  some flow:</p>
<div class="main_image"><img src="/assets/images/app-from-scratch/03-01.png" alt="Basic Workflow" /> <span class="imagetext">Basic app workflow</span></div>
<p>It&#8217;s not pretty folks, but that&#8217;s what sketching is. It&#8217;s fast and it&#8217;s just  to help you think and plan for the things you need.</p>
<h3>Bringing It to Life Photoshop</h3>
<p>Our developer is already ahead of us, thinking about the data they need and  how this app is going to actually work. So we&#8217;d better get started actually  designing here.</p>
<h4>Homepage (Logged In)</h4>
<p>This is the meat of our application so let&#8217;s start here. The list is obviously  the most important thing, so let&#8217;s keep the header small and keep the list  front and center. <strong>List items are big colored blocks with buttons for their  associated actions nearby.</strong> Below the list a box for entering new list items.</p>
<div class="main_image"><img src="/assets/images/app-from-scratch/03-02.png" alt="Home page logged in" /> <span class="imagetext">The home page as it appears when logged in</span></div>
<h4>Homepage (Logged Out)</h4>
<p>When logged out, the homepage is going to act more like a &#8220;sales&#8221; page. Not  that we plan to charge for it, but just to explain and get people interested  in using it. There isn&#8217;t much to say about a list app, so we&#8217;ll keep it simple.</p>
<div class="main_image"><img src="/assets/images/app-from-scratch/03-03.png" alt="Sales page" /> <span class="imagetext">When logged out, we&#8217;ll encourage the visitor to sign up</span></div>
<h4>Small Bits</h4>
<p>We&#8217;ve been designing long enough to know we might as well make the little  buttons into a separate file and keep them together as a <em><a href="http://css-tricks.com/css-sprites/">sprite</a></em> (a sprite is  multiple images combined into one to save HTTP requests, in our case, also the  rollover states). So we&#8217;ll do that and throw together a favicon while we&#8217;re  at it.</p>
<div class="main_image"><img src="/assets/images/app-from-scratch/03-04.png" alt="Tab sprite" /> <span class="imagetext">All the list item tabs</span></div>
<div class="main_image"><img src="/assets/images/app-from-scratch/03-05.png" alt="Favicon" /> <span class="imagetext">Favicon</span></div>
<h4>Registration</h4>
<p>Our intention with registration is going to be extremely simple. <strong>We&#8217;re going  to ask for a user&#8217;s email and that&#8217;s it.</strong> They will be sent an email with a  link in it to complete registration. The link in that email will &#8220;activate&#8221;  their account and they can choose the password at that time. So, our  registration page can be pretty darn simple.</p>
<div class="main_image"><img src="/assets/images/app-from-scratch/03-06.png" alt="Registration form" /> <span class="imagetext">The registration form</span></div>
<p>As small as this is, this registration page sets the stage for other forms. <strong>We  have a label/input pair here that can be used for any input/pair in any of our  site&#8217;s forms. </strong></p>
<h4>Account</h4>
<p>We&#8217;ll use the same form design as the registration page here. <strong>It&#8217;s not  cheating or being lazy, it&#8217;s good design through consistency! </strong></p>
<div class="main_image"><img src="/assets/images/app-from-scratch/03-07.png" alt="Account controls" /> <span class="imagetext">Account controls</span></div>
<h4>Buttons</h4>
<p>Notice the change in buttons. They are now big, orange and rounded. Much more  button-like don&#8217;t you think? Again for consistency, <strong>let&#8217;s make this the  default for all buttons across the site. </strong></p>
<div class="main_image"><img src="/assets/images/app-from-scratch/03-08.png" alt="Site buttons" /> <span class="imagetext">Site buttons, looking button-like</span></div>
<h3>Moving on</h3>
<p>The developer now has plenty to go on to start fleshing out the user  interactions for the site. And we have plenty to go on to start getting the  HTML and CSS for all this ready, and ultimately to AJAX this puppy up and get  it working.</p>
<div id="series-authors">
<h4>Series Authors</h4>
<div id="jason-series-author"><img style="margin: 0pt 10px 4px 0pt; float: left;" src="http://css-tricks.com/wp-content/csstricks-uploads/author-jason.jpg" alt="" width="125" height="125" /><strong>Jason Lengstorf</strong> is a software developer based in Missoula, MT. He is the author of <a href="http://www.amazon.com/gp/product/1430224738?ie=UTF8&amp;tag=ennudesi-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=1430224738">PHP for Absolute Beginners</a> and regularly blogs about programming. When not glued to his keyboard, he&rsquo;s likely standing in line for coffee, brewing his own beer, or daydreaming about being a Mythbuster.</div>
<div id="chris-series-author"><img style="margin: 0pt 0pt 4px 10px; float: right;" src="http://css-tricks.com/wp-content/csstricks-uploads/author-chris.jpg" alt="" width="125" height="125" /><strong>Chris Coyier</strong> is a designer currently living in Chicago, IL. He is the co-author of <a href="http://digwp.com/book/">Digging Into WordPress</a>, as well as blogger and speaker on all things design. Away from the computer, he is likely to be found yelling at Football coaches on TV or picking a banjo.</div>
</div>
<p>The post <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-3/">Creating an App from Scratch: Part 3</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-3/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Creating an App from Scratch: Part 2</title>
		<link>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-2/</link>
		<comments>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-2/#comments</comments>
		<pubDate>Mon, 23 Nov 2009 06:14:49 +0000</pubDate>
		<dc:creator>Jason Lengstorf</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-2</guid>
		<description><![CDATA[<p>Part 2 of the Creating an App from Scratch series, in which Chris Coyier and Jason Lengstorf cover, in great detail, the planning, design, building, and testing of an AJAX-powered web application based on PHP/MySQL. <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-2/" class="more-link">More</a></p><p>The post <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-2/">Creating an App from Scratch: Part 2</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<div id="series-header"><img src="/assets/images/app-from-scratch/02-header.jpg" alt="Creating a Web App from Scratch Part 2" /></div>
<div id="series-navigation">
<h5>All Series Navigation</h5>
<ul>
<li><a href="http://css-tricks.com/app-from-scratch-1-design">Part 1 &ndash; Planning the App: Basic Idea and Design</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-2/">Part 2 &ndash; Planning the App: Database Architecture and Development Approach</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-3/">Part 3 &#8211; Designing the App: Workflow Map and Photoshop Design</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-4-html-css">Part 4 &#8211; Designing the App: HTML and CSS</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-5/">Part 5 &#8211; Developing the App: User Interaction</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-6-ajax">Part 6 &#8211; Developing the App: Adding AJAX Interactivity</a></li>
<li><a href="/blog/creating-an-app-from-scratch-part-7/">Part 7 &#8211; Developing the App: List Interaction</a></li>
<li><a href="http://css-tricks.com/app-from-scratch-8-finishing">Part 8 &ndash; Wrapping Up</a></li>
<li> And finally&#8230; the application! <a href="http://coloredlists.com">Colored Lists</a></li>
</ul>
</div>
<h3>Where We&#8217;re At</h3>
<p>Up to this point, we&#8217;ve planned the way our app is going to look, as well as  given ourselves a basic idea of how the app is going to function. The next  step is to figure out what&#8217;s going to happen behind the scenes to allow our  app to work the way we&#8217;ve planned.</p>
<h3>Okay, So We Know How It Looks, but How Does It Work?</h3>
<p>In order to keep a list available after a user logs out of our app, we&#8217;ll  need to <strong>store list information in a database.</strong> And, of course, to access that  database we&#8217;re going to need some kind of server-side scripting language. For  this app, we made the choice to go with a combination of MySQL and PHP to  handle all our behind-the-scenes data handling and storage.</p>
<h3>Data Storage&mdash;Planning and Database Structure</h3>
<p>Our first step is to decide how we want to <strong>organize list data.</strong> Since this app  is fairly simple, we&#8217;ll only need three tables in our database. The first  table will store user information, and the second will store list information.  The third table will keep track of list items.</p>
<h4>Creating the Database</h4>
<p>Of course, before we can create our tables, we&#8217;ll need a database to work  with. For anyone working along at home, we&#8217;ll be operating under the  assumption that you&#8217;re building and testing locally (we recommend XAMPP).</p>
<p>Navigate to <tt>http://localhost/phpmyadmin</tt> and open the SQL tab. You can use the  GUI if you want, but we&#8217;re going to use raw SQL commands for learning  purposes. The database will be named <tt>cl_db</tt>, which is all the information  that is required to build the database. However, we want to make sure that our  users can use characters from any language in their lists, so it&#8217;s also a good  idea to specify the collation and character set of the database. We&#8217;ll be  using the <strong>UTF-8 character set with general collation</strong>, which supports  multilingual characters and is case-insensitive.</p>
<p>The command to create this database is:</p>
<pre class="brush: php">CREATE DATABASE `cl_db`
DEFAULT CHARACTER SET utf8
COLLATE utf8_general_ci;</pre>
<p>Execute this command from the SQL tab in phpMyAdmin and the new database will  become available. Now that we&#8217;ve got a database, we&#8217;re ready to build our  tables.</p>
<h4>Table 1: User Information</h4>
<p>Using our list app doesn&#8217;t require a high security clearance; all we need to  know is that you&#8217;ve got an email address and that it&#8217;s real. <strong>To determine that  an email address is real, we&#8217;ll be sending new users a confirmation link in an  email,</strong> which they need to follow before using our app. This means we need to  have a unique confirmation link and a place to store whether or not an account  has been verified.</p>
<p>Of course, we also need to <strong>store the user&#8217;s email address,</strong> and in the interest  of keeping redundant data storage to a minimum, we&#8217;ll <strong>assign each user a  unique numeric identifier. </strong></p>
<p>The MySQL command to build this table will look like this:</p>
<pre class="brush: php"><br />CREATE TABLE cl_db.users<br />(<br />    UserID      INT PRIMARY KEY AUTO_INCREMENT,<br />    Username    VARCHAR(150) NOT NULL,<br />    Password    VARCHAR(150),<br />    ver_code    VARCHAR(150),<br />    verified    TINYINT DEFAULT 0<br />)<br /></pre>
<h4>Table 2: List Information</h4>
<p>List information is fairly straightforward. <strong>Each list will have a unique  identifier, a unique URL, and the identifier of the user that owns the list.</strong> This helps us limit the amount of redundant information that needs to be  stored.</p>
<p>To build this table, execute the following MySQL command in phpMyAdmin&#8217;s SQL  tab:</p>
<pre class="brush: php"><br />CREATE TABLE cl_db.lists<br />(<br />    ListID      INT PRIMARY KEY AUTO_INCREMENT,<br />    UserID      INT NOT NULL,<br />    ListURL     VARCHAR(150)<br />)<br /></pre>
<h4>Table 3: List Items</h4>
<p>Finally, we need a table that will store our list items. <strong>Each list item needs  a unique identifier, the ID of the list it belongs to, and the information the  user enters as his or her list item.</strong> Also, to support features we&#8217;ll be adding  later on, we also need to <strong>keep a record of the item&#8217;s position and color.</strong> Execute this command in the SQL tab of phpMyAdmin:</p>
<pre class="brush: php">CREATE TABLE cl_db.list_items
(
    ListItemID       INT PRIMARY KEY AUTO_INCREMENT,
    ListID           INT NOT NULL,
    ListText         VARCHAR(150),
    ListItemDone     INT NOT NULL,
    ListItemPosition INT NOT NULL,
    ListItemColor    INT NOT NULL
)</pre>
<p><em>NOTE: The <tt>ListItemDone</tt> field was omitted in the original post of this article. It was added here after being <a href="/blog/creating-an-app-from-scratch-part-2/#cmnt395">pointed out in the comments by FuSi0N</a>.</em></p>
<div id="main_image"><img src="/assets/images/app-from-scratch/02-01.jpg" alt="The database with out three tables" /></p>
<p class="imagetext">The database with our three tables</p>
</div>
<p>Now we have our database and the three tables we&#8217;ll need to build our app.  Next, we&#8217;ll <strong>plan how we&#8217;re going to create and access our database information  using PHP. </strong></p>
<h3>Data Handling&mdash;Planning and Script Organization</h3>
<p>Before we start coding, it&#8217;s always a good idea to take a moment and map out  everything that needs to be done. That way, we can group tasks into logical  arrangements.</p>
<p>Because great code starts with great organization, we&#8217;ll be using an  object-oriented approach.</p>
<h4>Planning our PHP Classes</h4>
<p>Object-oriented programming provides an easy way to keep related functions  grouped together. After <a href="/blog/ITT %2310%3A Understanding OOP/">learning  object-oriented programming</a>, it becomes an  incredibly powerful tool that <strong>increases portability, readability, and  usability of scripts.</strong> Our app is pretty simple, so we&#8217;ll only need two  classes. The first class is going to handle user interactions, such as  <strong>registering, updating information, and logging in and out.</strong> The second class  will handle <strong>list interactions, such as adding, deleting, and moving list items.</strong></p>
<h4>User Actions Class</h4>
<p>Our first class, which we&#8217;ll name <tt>ColoredListsUsers</tt>, needs to <strong>handle all the  actions our app will perform that are user account-related.</strong> Again, this is a  pretty simple application, so when we map out everything that users can do  with their account, we end up with pretty short list:</p>
<ul>
<li><strong>Create an account</strong></li>
<li><strong>Verify the account</strong></li>
<li><strong>Update the account email address</strong></li>
<li><strong>Update the account password</strong></li>
<li><strong>Retrieve a forgotten password</strong></li>
<li><strong>Delete the account</strong></li>
</ul>
<p><strong>In addition to those methods, we&#8217;ll also need some support methods,</strong> such as  one that will send a verification email. We&#8217;ll define these methods as we  build the app in later installments of this series.</p>
<h4>List Actions Class</h4>
<p>The list actions class, which we&#8217;ll call <tt>ColoredListsItems</tt>, also has a pretty  short list of methods. This class will handle everything else our app does,  which is <strong>anything a user can do with his or her list items.</strong> The list of  available actions ends up looking like this:</p>
<ul>
<li><strong>Create a list item</strong></li>
<li><strong>Update a list item</strong></li>
<li><strong>Delete a list item</strong></li>
<li><strong>Change a list item&#8217;s position</strong></li>
<li><strong>Change a list item&#8217;s color</strong></li>
</ul>
<h4>Action Handling Scripts</h4>
<p>Finally, we&#8217;ll need a couple action-handling scripts. These will <strong>determine  what the user&#8217;s desired action is, create an instance of the proper object,  and call the correct method.</strong> As we build our app, we&#8217;ll go into more detail on  how these scripts will work.</p>
<h3>Moving On</h3>
<p>In our next installment of this series, we&#8217;ll <strong>create the application workflow.</strong> Make sure you&#8217;re subscribed to <a href="http://css-tricks.com">CSS-Tricks</a> so you don&#8217;t miss out!</p>
<div id="series-authors">
<h4>Series Authors</h4>
<div id="jason-series-author"><img style="margin: 0pt 10px 4px 0pt; float: left;" src="http://css-tricks.com/wp-content/csstricks-uploads/author-jason.jpg" alt="" width="125" height="125" /><strong>Jason Lengstorf</strong> is a software developer based in Missoula, MT. He is the author of <a href="http://www.amazon.com/gp/product/1430224738?ie=UTF8&amp;tag=ennudesi-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=1430224738">PHP for Absolute Beginners</a> and regularly blogs about programming. When not glued to his keyboard, he&rsquo;s likely standing in line for coffee, brewing his own beer, or daydreaming about being a Mythbuster.</div>
<div id="chris-series-author"><img style="margin: 0pt 0pt 4px 10px; float: right;" src="http://css-tricks.com/wp-content/csstricks-uploads/author-chris.jpg" alt="" width="125" height="125" /><strong>Chris Coyier</strong> is a designer currently living in Chicago, IL. He is the co-author of <a href="http://digwp.com/book/">Digging Into WordPress</a>, as well as blogger and speaker on all things design. Away from the computer, he is likely to be found yelling at Football coaches on TV or picking a banjo.</div>
</div>
<p>The post <a href="http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-2/">Creating an App from Scratch: Part 2</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.copterlabs.com/blog/creating-an-app-from-scratch-part-2/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>How to Implement Natural Sorting in MySQL</title>
		<link>http://www.copterlabs.com/blog/natural-sorting-in-mysql/</link>
		<comments>http://www.copterlabs.com/blog/natural-sorting-in-mysql/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 19:21:06 +0000</pubDate>
		<dc:creator>Jason Lengstorf</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.copterlabs.com/blog/natural-sorting-in-mysql</guid>
		<description><![CDATA[<p>A quick tip that allows strings to be sorted in numerical order, avoiding the test1, test10, test2, etc. issue. <a href="http://www.copterlabs.com/blog/natural-sorting-in-mysql/" class="more-link">More</a></p><p>The post <a href="http://www.copterlabs.com/blog/natural-sorting-in-mysql/">How to Implement Natural Sorting in MySQL</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<h3>A Workaround to Support Natural Sorting in MySQL</h3>
<p>Several times in the last few projects I&#8217;ve built, I&#8217;ve come across the need to sort alphanumeric rows in a database by number (i.e. entry1, entry2, entry3, etc.). If you&#8217;ve ever tried to do this, you know that natural sorting in MySQL with alphanumeric entries is a pain.</p>
<h3>The Data</h3>
<p>For our purposes, we&#8217;ll be using the following table:</p>
<pre class="brush: php">Table: sorting_test
 -------------------------- -------------
| alphanumeric VARCHAR(75) | integer INT |
 -------------------------- -------------
| test1                    | 1           |
| test2                    | 2           |
| test3                    | 3           |
| test4                    | 4           |
| test5                    | 5           |
| test6                    | 6           |
| test7                    | 7           |
| test8                    | 8           |
| test9                    | 9           |
| test10                   | 10          |
| test11                   | 11          |
| test12                   | 12          |
 -------------------------- -------------</pre>
<h3>The Problem</h3>
<p>Sorting by the column <tt>integer</tt>, of course, presents no problems.</p>
<pre class="brush: php">Query: SELECT alphanumeric, integer
       FROM sorting_test
       ORDER BY integer
 -------------------------- -------------
| alphanumeric VARCHAR(75) | integer INT |
 -------------------------- -------------
| test1                    | 1           |
| test2                    | 2           |
| test3                    | 3           |
| test4                    | 4           |
| test5                    | 5           |
| test6                    | 6           |
| test7                    | 7           |
| test8                    | 8           |
| test9                    | 9           |
| test10                   | 10          |
| test11                   | 11          |
| test12                   | 12          |
 -------------------------- -------------</pre>
<p>However, when we try sorting by the <tt>alphanumeric</tt> column, we get unexpected results:</p>
<pre class="brush: php">Query: SELECT alphanumeric, integer
       FROM sorting_test
       ORDER BY alphanumeric
 -------------------------- -------------
| alphanumeric VARCHAR(75) | integer INT |
 -------------------------- -------------
| test1                    | 1           |
| test10                   | 10          |
| test11                   | 11          |
| test12                   | 12          |
| test2                    | 2           |
| test3                    | 3           |
| test4                    | 4           |
| test5                    | 5           |
| test6                    | 6           |
| test7                    | 7           |
| test8                    | 8           |
| test9                    | 9           |
 -------------------------- -------------</pre>
<p>Obviously, this is not the desired outcome. Since we&#8217;re sorting alphabetically, the entries are actually in the correct order, but we need to find a way to sort numerically.</p>
<p>This is called &#8220;natural sorting&#8221; in MySQL. Actually, it&#8217;s called natural sorting everywhere. What it means is, in layman&#8217;s terms, a human being would <em>naturally</em> sort the items with the count in order.</p>
<p>However, as far as MySQL is concerned the above output is alphabetical. If you swap the numbers for letters, the way MySQL sorts these items makes much more sense:</p>
<pre class="brush: php">Query: SELECT alphanumeric, integer
       FROM sorting_test
       ORDER BY alphanumeric
 -------------------------- -------------
| alphanumeric VARCHAR(75) | integer INT |
 -------------------------- -------------
| testA                    | 1           |
| testAA                   | 10          |
| testAB                   | 11          |
| testAC                   | 12          |
| testB                    | 2           |
| testC                    | 3           |
| testD                    | 4           |
| testE                    | 5           |
| testF                    | 6           |
| testG                    | 7           |
| testH                    | 8           |
| testI                    | 9           |
 -------------------------- -------------</pre>
<h3>The Solution</h3>
<p>There are a whole lot of solutions out there if you hit up Google, and you can, of course, just use the <a href="http://php.net/manual/en/function.natsort.php&quot;"><code>natsort()</code></a> function in PHP, but it&#8217;s simple enough to accomplish natural sorting in MySQL: sort by length first, then the column value.</p>
<pre class="brush: php">Query: SELECT alphanumeric, integer
       FROM sorting_test
       ORDER BY LENGTH(alphanumeric), alphanumeric
 -------------------------- -------------
| alphanumeric VARCHAR(75) | integer INT |
 -------------------------- -------------
| test1                    | 1           |
| test2                    | 2           |
| test3                    | 3           |
| test4                    | 4           |
| test5                    | 5           |
| test6                    | 6           |
| test7                    | 7           |
| test8                    | 8           |
| test9                    | 9           |
| test10                   | 10          |
| test11                   | 11          |
| test12                   | 12          |
 -------------------------- -------------</pre>
<p>This works because the first nine entries are 5 characters long, with the tenth, eleventh, and twelfth entries at 6 characters; this creates two groups of entries that are then sub-sorted, resulting in our desired order. This is called &#8220;natural sorting&#8221;.</p>
<h3>Summary</h3>
<p>This is a quick tip, but a useful one. Do you have a better way of forcing natural sorting in MySQL? Let me know in the comments!</p>
<p>The post <a href="http://www.copterlabs.com/blog/natural-sorting-in-mysql/">How to Implement Natural Sorting in MySQL</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.copterlabs.com/blog/natural-sorting-in-mysql/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JSON: What It Is, How It Works, &amp; How to Use It</title>
		<link>http://www.copterlabs.com/blog/json-what-it-is-how-it-works-how-to-use-it/</link>
		<comments>http://www.copterlabs.com/blog/json-what-it-is-how-it-works-how-to-use-it/#comments</comments>
		<pubDate>Thu, 02 Jul 2009 10:24:03 +0000</pubDate>
		<dc:creator>Jason Lengstorf</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[introduction]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[walkthrough]]></category>

		<guid isPermaLink="false">http://www.copterlabs.com/blog/json-what-it-is-how-it-works-how-to-use-it</guid>
		<description><![CDATA[<p>This article will cover the following: What is JSON, why does it matter, and how do we use JSON in a project? We&#8217;ll also use our newfound skills with JSON at the end of this project to build a quick app that loads photos from Flickr without requiring a page refresh. <a href="http://www.copterlabs.com/blog/json-what-it-is-how-it-works-how-to-use-it/" class="more-link">More</a></p><p>The post <a href="http://www.copterlabs.com/blog/json-what-it-is-how-it-works-how-to-use-it/">JSON: What It Is, How It Works, &amp; How to Use It</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<p>This week I want to cover a topic that I feel has become an important part of any developer&#8217;s toolkit: the ability to load and manipulate JSON feeds from other sites via AJAX. Many sites are sharing data using JSON in addition to RSS feeds nowadays, and with good reason: <strong>JSON feeds can be loaded asynchronously much more easily than XML/RSS.</strong>This article will cover the following:</p>
<ul>
<li>What is JSON?</li>
<li>Why does JSON matter?</li>
<li>How do we load JSON into a project?</li>
</ul>
<p>We&#8217;ll also use our newfound skills with JSON at the end of this project to <strong>build a quick app that loads photos from Flickr without requiring a page refresh.</strong> <span class="demolink"><a href="/demo/reading-json">See the Demo</a> | <a href="/demo/EnnuiDesign_reading-json.zip">Download the Source</a></span></p>
<h3>What Is JSON?</h3>
<p><a href="http://en.wikipedia.org/wiki/JSON">JSON</a> is short for <strong>JavaScript Object Notation</strong>, and is <em>a way to store information in an organized, easy-to-access manner.</em>In a nutshell, it gives us a human-readable collection of data that we can access in a really logical manner.</p>
<h4>Storing JSON Data</h4>
<p>As a simple example, information about me might be written in JSON as follows:</p>
        <script src="https://gist.github.com/2760279.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760279">https://gist.github.com/2760279</a>
            </p>
        </noscript>

<p>This creates an object that we access using the variable <tt>jason</tt>. By enclosing the variable&#8217;s value in curly braces, we&#8217;re indicating that the value is an object. Inside the object, we can declare any number of properties using a <tt>"property-name" : "property-value"</tt> pairing, separated by commas. To access the information stored in <tt>jason</tt>, we can <strong>simply refer to the name of the property we need.</strong>For instance, to access information about me, we could use the following snippets:</p>
        <script src="https://gist.github.com/2760312.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760312">https://gist.github.com/2760312</a>
            </p>
        </noscript>

<h4>Storing JSON Data in Arrays</h4>
<p>A slightly more complicated example involves storing two people in one variable. To do this, we <strong>enclose multiple objects in square brackets,</strong>which signifies an array. For instance, if I needed to include information about myself and my brother in one variable, I might use the following:</p>
        <script src="https://gist.github.com/2760314.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760314">https://gist.github.com/2760314</a>
            </p>
        </noscript>

<p>To access this information, we need to access the array index of the person we wish to access. For example, we would use the following snippet to access info stored in <tt>family</tt>:</p>
<p class="brush: js">        <script src="https://gist.github.com/2760322.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760322">https://gist.github.com/2760322</a>
            </p>
        </noscript>
</p>
<p><em><strong>NOTE:</strong> This is beneficial if it will be necessary to loop through stored information, as it lends itself to a <tt>for</tt> loop with an automatically incrementing value.</em></p>
<h4>Nesting JSON Data</h4>
<p>Another way to store multiple people in our variable would be to <strong>nest objects.</strong>To do this, we would create something similar to the following:</p>
<p class="brush: js">        <script src="https://gist.github.com/2760326.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760326">https://gist.github.com/2760326</a>
            </p>
        </noscript>
</p>
<p>Accessing information in nested objects is a little easier to understand; to access information in the object, we would use the following snippet:</p>
<p class="brush: js">        <script src="https://gist.github.com/2760328.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760328">https://gist.github.com/2760328</a>
            </p>
        </noscript>
</p>
<p>Nested JSON and arrays can be combined as needed to store as much data as necessary.</p>
<h3>Why Does JSON Matter?</h3>
<p>With the rise of <a href="http://en.wikipedia.org/wiki/Ajax_(programming)">AJAX</a>-powered sites, it&#8217;s becoming more and more important for sites to be able to load data <strong>quickly and <em>asynchronously</em>,</strong> or in the background without delaying page rendering. Switching up the contents of a certain element within our layouts without requiring a page refresh adds a &#8220;wow&#8221; factor to our applications, not to mention the added convenience for our users. Because of the popularity and ease of social media, many sites rely on the content provided by sites such as Twitter, Flickr, and others. These sites provide RSS feeds, which are easy to import and use on the server-side, but if we try to load them with AJAX, we run into a wall: <strong><em>we can only load an RSS feed if we&#8217;re requesting it from the same domain it&#8217;s hosted on.</em></strong> An attempt to load my Flickr account&#8217;s RSS feed via jQuery&#8217;s <a href="http://docs.jquery.com/Ajax/jQuery.ajax"><tt>$.ajax()</tt></a>method results in the following JavaScript error:</p>
<p class="brush: html">        <script src="https://gist.github.com/2760335.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760335">https://gist.github.com/2760335</a>
            </p>
        </noscript>
</p>
<p>JSON allows us to overcome the cross-domain issue because <strong>we can use a method called <a href="http://remysharp.com/2007/10/08/what-is-jsonp/">JSONP</a> that uses a callback function to send the JSON data back to our domain.</strong>It&#8217;s this capability that makes JSON so incredibly useful, as it opens up a lot of doors that were previously difficult to work around.</p>
<h3>How Do We Load JSON into a Project?</h3>
<p>One of the easiest ways to load JSON data into our web applications is to <strong>use the <a href="http://docs.jquery.com/Ajax/jQuery.ajax"><tt>$.ajax()</tt></a> method available in the jQuery library.</strong>The ease of retrieving data will vary based on the site providing the data, but a simple example might look like this:</p>
<p class="brush: js">        <script src="https://gist.github.com/2760340.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760340">https://gist.github.com/2760340</a>
            </p>
        </noscript>
</p>
<p>This example would request the latest feed items in JSON format and output them to the browser. Obviously, we wouldn&#8217;t want to output raw JSON data to the browser, but this example shows the basics of loading JSON from an external source.</p>
<h3>A Practical Example: Loading Flickr Streams with JSON and jQuery</h3>
<p><span class="demolink"><a href="/demo/reading-json">See the Demo</a> | <a href="/demo/EnnuiDesign_reading-json.zip">Download the Source</a></span> To show how JSON works in a real-world example, let&#8217;s <strong>load photos from Flickr using jQuery and the JSON version of Flickr&#8217;s &#8220;Latest&#8221; photo feed.</strong></p>
<h4>Step 1: Create the AJAX Request</h4>
<p>Flickr&#8217;s photostream feeds are relatively easy to access. All users have a unique ID number, which we will send as part of the request to this URL.</p>
<p class="brush: php">        <script src="https://gist.github.com/2760345.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760345">https://gist.github.com/2760345</a>
            </p>
        </noscript>
</p>
<p>The request we need to send asks for the latest photos from the user in question, along with flags asking for a JSON-formatted response. The request we need to send will look like this:</p>
<p class="brush: php">        <script src="https://gist.github.com/2760354.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760354">https://gist.github.com/2760354</a>
            </p>
        </noscript>
</p>
<p>In the above example, <strong>XXXXXXXX@NXX</strong> needs to be replaced with the user&#8217;s ID. We&#8217;ll be writing a function, so the user&#8217;s ID will be passed as an argument called <tt>flickrID</tt>. Our function will be called <tt>loadFlickr()</tt>. Let&#8217;s create the function that will load our JSON response:</p>
<p class="brush: js">        <script src="https://gist.github.com/2760361.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760361">https://gist.github.com/2760361</a>
            </p>
        </noscript>
</p>
<p>The returned JSON data will look something like this (note that I&#8217;ve removed all but one of the returned photos for the sake of brevity):</p>
<p class="brush: js">        <script src="https://gist.github.com/2760362.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760362">https://gist.github.com/2760362</a>
            </p>
        </noscript>
</p>
<h4>Step 2: Process the JSON Data</h4>
<p>What we&#8217;re going to do is <strong>display the thumbnails of the latest 16 photos, which will link to the medium-sized display of the image.</strong> The Flickr JSON is a little confusing, and it doesn&#8217;t provide a direct link to the thumbnail version of our photos, so we&#8217;ll have to use some trickery on our end to get to it, which we&#8217;ll cover in just a moment. Each photo entry is stored in an array called <tt>items</tt>, which we access in our AJAX call using <tt>feed.items</tt>. To get to the data about each entry, we&#8217;ll loop through the items until we&#8217;ve either hit the last available photo or 16 total photos; whichever comes first. Let&#8217;s modify our function and set up the loop:</p>
<p class="brush: js">        <script src="https://gist.github.com/2760364.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760364">https://gist.github.com/2760364</a>
            </p>
        </noscript>
</p>
<p>The element we&#8217;re interested in is the &#8220;m&#8221; element stored within the &#8220;media&#8221; element. This can be accessed within our loop using <tt>feed.items[i].media.m</tt>. <strong>We&#8217;re going to run a regular expression on this value to get both the medium and thumbnail image paths, which we&#8217;ll assemble into a linked thumbnail image.</strong> Then, we&#8217;ll push the newly assembled HTML into the array of thumbs we created. After we&#8217;ve finished the loop, we&#8217;ll <strong>combine all the images into one string of HTML</strong>and replace the contents of our display element with the loaded thumbnails. Let&#8217;s add this functionality to our script:</p>
<p class="brush: js">        <script src="https://gist.github.com/2760365.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760365">https://gist.github.com/2760365</a>
            </p>
        </noscript>
</p>
<p>Note that I&#8217;ve also added a function called <tt>addLB()</tt> to the end of this function; this adds the <a href="http://leandrovieira.com/projects/jquery/lightbox/">lightbox</a>effect to our thumbnails, which is purely for aesthetics.</p>
<h4>Step 3: Call Our Function</h4>
<p>At this point, we&#8217;re ready to call our function. To load my Flickr stream, we would need to call our function as follows:</p>
<p class="brush: js">        <script src="https://gist.github.com/2760370.js"> </script>
        <noscript>
            <p>
                Since JavaScript is disabled, you'll need to view this gist on 
                GitHub: 
                <a href="https://gist.github.com/2760370">https://gist.github.com/2760370</a>
            </p>
        </noscript>
</p>
<p>The example posted will pull multiple users&#8217; photostreams into the containing box without causing a page refresh. Look at the source code on <a href="/demo/reading-json">the demo</a> to see how it was done. <em><strong>NOTE:</strong> Keep in mind that this demo was to show how to load JSON data, and not on how to implement the code to call the function. The JavaScript calls are inline, which should NOT be used in a production script.</em> <span class="demolink"><a href="/demo/reading-json">See the Demo</a> | <a href="/demo/EnnuiDesign_reading-json.zip">Download the Source</a></span></p>
<h3>Summary</h3>
<p>Have you used JSON before? Is there anything you&#8217;d like to clarify or see further clarified about JSON? Let me know in the comments!</p>
<p>The post <a href="http://www.copterlabs.com/blog/json-what-it-is-how-it-works-how-to-use-it/">JSON: What It Is, How It Works, &amp; How to Use It</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.copterlabs.com/blog/json-what-it-is-how-it-works-how-to-use-it/feed/</wfw:commentRss>
		<slash:comments>53</slash:comments>
		</item>
		<item>
		<title>Easily Create External Links Without the Target Attribute</title>
		<link>http://www.copterlabs.com/blog/easily-create-external-links-without-the-target-attribute/</link>
		<comments>http://www.copterlabs.com/blog/easily-create-external-links-without-the-target-attribute/#comments</comments>
		<pubDate>Tue, 16 Jun 2009 18:27:33 +0000</pubDate>
		<dc:creator>Jason Lengstorf</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.copterlabs.com/blog/easily-create-external-links-without-the-target-attribute</guid>
		<description><![CDATA[<p>I&#8217;m a big fan of keeping sites valid in XHTML 1.0 Strict. When I first started paying attention to standards, one of the things that stumped me right off the bat was the use of external links. This tip shows you how to use jQuery to keep your code valid AND have links open externally. <a href="http://www.copterlabs.com/blog/easily-create-external-links-without-the-target-attribute/" class="more-link">More</a></p><p>The post <a href="http://www.copterlabs.com/blog/easily-create-external-links-without-the-target-attribute/">Easily Create External Links Without the Target Attribute</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></description>
				<content:encoded><![CDATA[<p>Today&#8217;s tip is extremely short and simple, and to a lot of folks may be a  &#8220;Duh!&#8221; sort of tip, but I felt it was worth sharing.</p>
<p>I&#8217;m a big fan of <strong>keeping sites valid in XHTML 1.0 Strict.</strong> When I first started  paying attention to standards, one of the things that stumped me right off the  bat was the use of external links.</p>
<h3>The Problem with <tt>target="_blank"</tt></h3>
<p>As I&#8217;m sure most people know, <strong>the use of the <tt>target</tt> attribute isn&#8217;t  considered valid.</strong> However, in order to open links in a new page, the only tool  provided by HTML is the <tt>target</tt> attribute!</p>
<p>I had been creating external links for as long as I could remember using the  following format:</p>
<pre class="brush: html">
&lt;a href="http://example.com" target="_blank"&gt;External link&lt;/a&gt;
</pre>
<h3>The Fix: <tt>rel="external"</tt></h3>
<h4>The HTML</h4>
<p>When I started using <a href="http://jquery.com">jQuery</a>, I stumbled across  this little gem that allowed me to have my valid code <em>and</em> external  links with one simple line of code:</p>
<pre class="brush: html">
&lt;a href="http://example.com" rel="external"&gt;External link&lt;/a&gt;
</pre>
<p><strong>The use of <tt>rel="external"</tt> is perfectly valid,</strong> and doesn&#8217;t cause any  problems at all. However, this attribute won&#8217;t work by itself. In order to  cause the links to open in a new page, we first need to employ a jQuery  one-liner.</p>
<h4>The JavaScript</h4>
<p>At the bottom of any page that features external links, we need to include one  line of jQuery code (and jQuery itself, of course):</p>
<pre class="brush: html">
&lt;script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
	$('a[rel="external"]').attr('target', '_blank');
&lt;/script&gt;
</pre>
<p>And that&#8217;s it. Seriously.</p>
<p>This method degrades gracefully: if the user doesn&#8217;t have JavaScript, the link  will open in the same window. This method is easy, lightweight, and most  importantly, <strong>valid XHTML 1.0 Strict.</strong></p>
<h3>Summary</h3>
<p><strong>Writing valid code should be high on any developer&#8217;s to-do list,</strong> and using the  <tt>rel="external"</tt> trick is an easy way to take yourself one step closer  to completely valid sites.</p>
<p>Do you have any tricks to keep sites valid? How about a raw JavaScript,  MooTools, or other library method of doing the <tt>rel="external"</tt> trick? Share it in the comments!</p>
<p>The post <a href="http://www.copterlabs.com/blog/easily-create-external-links-without-the-target-attribute/">Easily Create External Links Without the Target Attribute</a> appeared first on <a href="http://www.copterlabs.com">Copter Labs</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.copterlabs.com/blog/easily-create-external-links-without-the-target-attribute/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
