<?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>Chris Morrell &#187; Web Development</title>
	<atom:link href="http://cmorrell.com/webdev/feed" rel="self" type="application/rss+xml" />
	<link>http://cmorrell.com</link>
	<description>The personal home page of Chris Morrell</description>
	<lastBuildDate>Thu, 02 Feb 2012 16:34:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Top WordPress Actions/Filters</title>
		<link>http://cmorrell.com/webdev/top-wordpress-actions-filters-901</link>
		<comments>http://cmorrell.com/webdev/top-wordpress-actions-filters-901#comments</comments>
		<pubDate>Tue, 21 Sep 2010 03:06:19 +0000</pubDate>
		<dc:creator>Chris M.</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://cmorrell.com/?p=901</guid>
		<description><![CDATA[Today I downloaded just about every WordPress plugin that exists (or the top 8,000+, at least) and parsed out the actions and filters that each plugin hooks into.  I&#8217;m going to be looking at that data to help determine the &#8230; <a href="http://cmorrell.com/webdev/top-wordpress-actions-filters-901">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Today I downloaded just about every WordPress plugin that exists (or the top 8,000+, at least) and parsed out the actions and filters that each plugin hooks into.  I&#8217;m going to be looking at that data to help determine the key places that a CMS needs to be flexible.  But until I have time to play with the data, I thought I&#8217;d post the top WordPress hooks, taken from 8,240 of the most popular plugins hosted on WordPress.org.</p>
<p><a href="http://cdn1.cmorrell.com/wp-content/uploads/wordpress-top-hooks.png"><img class="alignnone size-full wp-image-902" title="wordpress-top-hooks" src="http://cdn1.cmorrell.com/wp-content/uploads/wordpress-top-hooks.png" alt="" width="429" height="416" /></a></p>
<p>It makes sense that initialization, filtering the page content, and adding administrative features are at the top of the list.  It&#8217;ll be more interesting to see whats a little further down.  I&#8217;ll post more as I have time to make sense of the data.</p>
<div class="su-linkbox" id="post-901-linkbox"><div class="su-linkbox-label">Link to this post!</div><div class="su-linkbox-field"><input type="text" value="&lt;a href=&quot;http://cmorrell.com/webdev/top-wordpress-actions-filters-901&quot;&gt;Top WordPress Actions/Filters&lt;/a&gt;" onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" /></div></div>]]></content:encoded>
			<wfw:commentRss>http://cmorrell.com/webdev/top-wordpress-actions-filters-901/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Zend Debugger Safari Toolbar</title>
		<link>http://cmorrell.com/webdev/zend-debugger-safari-toolbar-820</link>
		<comments>http://cmorrell.com/webdev/zend-debugger-safari-toolbar-820#comments</comments>
		<pubDate>Thu, 01 Jul 2010 21:42:53 +0000</pubDate>
		<dc:creator>Chris M.</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[zend]]></category>
		<category><![CDATA[zend studio]]></category>

		<guid isPermaLink="false">http://cmorrell.com/?p=820</guid>
		<description><![CDATA[Update: It turns out Safari is more problematic than Firefox, so I&#8217;ve switched back.  I have no plans to finish this project.  Feel free to fork it on GitHub. When Safari 5 came out I decided to make the switch. &#8230; <a href="http://cmorrell.com/webdev/zend-debugger-safari-toolbar-820">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong>Update:</strong> It turns out Safari is more problematic than Firefox, so I&#8217;ve switched back.  I have no plans to finish this project.  Feel free to fork it on <a href="http://github.com/inxilpro/Zend-Debugger-Safari-Toolbar" target="_blank">GitHub</a>.</p>
<p>When Safari 5 came out I decided to make the switch.  The new Safari developer tools rival Firebug, Safari now supports extensions, and Firefox has been causing all sorts of problems for me lately (20-second freezes, choppy video, etc).  There were three things that I knew I couldn&#8217;t live without…</p>
<p><span id="more-820"></span>Those were:</p>
<ul>
<li>AdBlock</li>
<li>Delicious.com Integration</li>
<li>The Zend Studio Toolbar</li>
</ul>
<p>The first two were ported to Safari within days (if not hours) of the Safari 5 release.  The third is likely to take a while, so I decided to put together my own version for the time-being.  Right now it&#8217;s very much in an &#8220;alpha&#8221; stage.  It only supports the &#8220;debug current page&#8221; command, and it hasn&#8217;t been tested all that thoroughly.  That said, I plan on developing this over the next few weeks to mirror most of the features available in the current Zend Studio Toolbar for Firefox and MSIE.</p>
<p>I&#8217;m also adding some features of my own.  Namely, the toolbar remembers what domains you&#8217;ve enabled debugging on, and only shows itself on those domains.  There&#8217;s a browser button that you can use to toggle debugging, and in the future I want to add an indicator when the page you&#8217;re on supports debugging.</p>
<p>If you develop with Zend Studio and Safari, please <a href="http://cmorrell.com/safari-extensions/zend-debugger">check out the current version of the extension</a>.  I could really use some feedback from other folks (particularly those who have other workflows from me).</p>
<div class="su-linkbox" id="post-820-linkbox"><div class="su-linkbox-label">Link to this post!</div><div class="su-linkbox-field"><input type="text" value="&lt;a href=&quot;http://cmorrell.com/webdev/zend-debugger-safari-toolbar-820&quot;&gt;Zend Debugger Safari Toolbar&lt;/a&gt;" onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" /></div></div>]]></content:encoded>
			<wfw:commentRss>http://cmorrell.com/webdev/zend-debugger-safari-toolbar-820/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Better Zend Framework Documentation</title>
		<link>http://cmorrell.com/webdev/zf/zend-framework-documentation-777</link>
		<comments>http://cmorrell.com/webdev/zf/zend-framework-documentation-777#comments</comments>
		<pubDate>Tue, 30 Mar 2010 13:07:09 +0000</pubDate>
		<dc:creator>Chris M.</dc:creator>
				<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[wishlist]]></category>

		<guid isPermaLink="false">http://cmorrell.com/?p=777</guid>
		<description><![CDATA[If you&#8217;ve every tried to navigate the Zend Framework documentation&#8217;s longer pages you&#8217;ve probably looked everywhere for a table of contents.  Sure, there&#8217;s a TOC for the major sections of the component, but if you&#8217;re looking for a specific part &#8230; <a href="http://cmorrell.com/webdev/zf/zend-framework-documentation-777">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve every tried to navigate the <a href="http://framework.zend.com/manual/en/zend.filter.set.html" target="_blank">Zend Framework documentation&#8217;s longer pages</a> you&#8217;ve probably looked everywhere for a table of contents.  Sure, there&#8217;s a TOC for the major sections of the component, but if you&#8217;re looking for a specific part of a page (or an overview of what that page covers) you&#8217;re out of luck.  For example, take a look at the Zend_Validate <a href="http://framework.zend.com/manual/en/zend.validate.set.html" target="_blank">list of standard validation classes</a>.  Now try to find the documentation on the URI validator.  Can&#8217;t find it?  That&#8217;s &#8217;cause it doesn&#8217;t exist.  Too bad you had to scroll down through 39 page-lengths&#8217; worth of documentation to find that out.</p>
<p><span id="more-777"></span>Wouldn&#8217;t it be nice if you&#8217;d had something like this:</p>
<p><img class="alignnone size-full wp-image-779" title="Zend Validate TOC" src="http://cdn1.cmorrell.com/wp-content/uploads/2010/03/Zend_Validate_TOC.png" alt="" width="281" height="338" /></p>
<p>Well, there are two things you can do.  The first is to vote on <a href="http://framework.zend.com/issues/browse/ZF-9509" target="_blank">ZF-9509</a> and <a href="http://framework.zend.com/issues/browse/ZF-9508" target="_blank">ZF-9508</a>.  But until the documentation is fixed, you can download my Greasemonkey script that gives you a page TOC right now:</p>
<p><a href="http://userscripts.org/scripts/show/72873" target="_blank">[Download id not defined]</a></p>
<p>Hope you enjoy!</p>
<div class="su-linkbox" id="post-777-linkbox"><div class="su-linkbox-label">Link to this post!</div><div class="su-linkbox-field"><input type="text" value="&lt;a href=&quot;http://cmorrell.com/webdev/zf/zend-framework-documentation-777&quot;&gt;Better Zend Framework Documentation&lt;/a&gt;" onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" /></div></div>]]></content:encoded>
			<wfw:commentRss>http://cmorrell.com/webdev/zf/zend-framework-documentation-777/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Automatic Virtual Hosts w/ Proxy Auto-Config</title>
		<link>http://cmorrell.com/webdev/automatic-virtual-hosts-w-proxy-auto-config-768</link>
		<comments>http://cmorrell.com/webdev/automatic-virtual-hosts-w-proxy-auto-config-768#comments</comments>
		<pubDate>Thu, 25 Mar 2010 19:50:34 +0000</pubDate>
		<dc:creator>Chris M.</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://cmorrell.com/?p=768</guid>
		<description><![CDATA[I often tell my co-workers that if they&#8217;re doing the same basic thing over and over again, to let me know, because there&#8217;s probably a way to automate it.  That&#8217;s why whenever I used to start a new web development &#8230; <a href="http://cmorrell.com/webdev/automatic-virtual-hosts-w-proxy-auto-config-768">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I often tell my co-workers that if they&#8217;re doing the same basic thing over and over again, to let me know, because there&#8217;s probably a way to automate it.  That&#8217;s why whenever I used to start a new web development project I&#8217;d feel a twinge of guilt.  Does this look familiar?</p>
<ul>
<li>Create /path/to/vhosts/projectname/public</li>
<li>Edit /etc/hosts to add <code>127.0.0.1 projectname.localhost</code></li>
<li>Edit /path/to/httpd-vhosts.conf to add a new <code>&lt;VirtualHost&gt;</code> directive for projectname.localhost</li>
<li>Repeat for each new project</li>
</ul>
<p>It&#8217;s not a big deal—maybe a two minute distraction—but it always bugged me.  I&#8217;d looked into automating this before, but it always led to me installing a DNS server on my local machine, which is something I don&#8217;t particularly want to do.  Then, just a few days ago, I accidentally stumbled on to a fantastic cross-platform solution.</p>
<p><span id="more-768"></span>First let&#8217;s start with Apache, which was always the un-problematic part of the equation.  There&#8217;s a great Apache extension called <a href="http://httpd.apache.org/docs/2.0/mod/mod_vhost_alias.html" target="_blank">mod_vhost_alias</a> that was made to do just this.  All you need is one slightly modified <code>&lt;VirtualHost&gt;</code> directive and you&#8217;re set:</p>
<pre class="brush: plain; title: ; notranslate">
&lt;VirtualHost *:80&gt;
    ServerAdmin webmaster@localhost
    VirtualDocumentRoot &quot;/path/to/vhosts/%1/public&quot;
    ServerName subdomains.localhost
    ServerAlias *.localhost
    LogFormat &quot;%V %h %l %u %t \&quot;%r\&quot; %s %b&quot; vcommon
    ErrorLog &quot;logs/vhosts-error_log&quot;
    CustomLog &quot;logs/vhosts-access_log&quot; vcommon
&lt;/VirtualHost&gt;
</pre>
<p>And you&#8217;re also going to want to set directory permissions on all those directories:</p>
<pre class="brush: plain; title: ; notranslate">
&lt;Directory &quot;/path/to/vhosts/*/public&quot;&gt;
    Options Indexes FollowSymLinks
    AllowOverride All
    Order allow,deny
    Allow from all
&lt;/Directory&gt;
</pre>
<p>You&#8217;ll also probably want to turn <code>UseCanonicalName Off</code>.  Now Apache is set up to map <strong>anything</strong>.localhost to /path/to/vhosts/<strong>anything</strong>/public.  The problem is, your computer still doesn&#8217;t know that it should be handling http://anything.localhost.  That&#8217;s where the proxy auto-config file comes into play.</p>
<p>Proxy Auto-Config files, or PAC files, were designed to help your browser determine if and when it should use a proxy.  PAC files are actually just simple JavaScript files with one function that takes URL and Host Name arguments and returns a string telling the browser what to do.  Often this would be used to send certain traffic through a proxy, or proxy certain traffic at certain times of the week (it might be useful as a distraction-blocker as well), but in our case we&#8217;re going to use it to forward all <strong>.localhost</strong> traffic back to our local web server.</p>
<p>Just create a file called <strong>localhost.pac</strong> and put the following inside it:</p>
<pre class="brush: plain; title: ; notranslate">
function FindProxyForURL(url, host)
{
	if (dnsDomainIs(host, &quot;.localhost&quot;)) {
		return &quot;PROXY localhost&quot;;
	}

	return &quot;DIRECT&quot;;
}
</pre>
<p>Basically what this file is saying is, if the domain is <strong>*.localhost</strong>, send it to localhost, otherwise just connect directly.  All you have to do is save that file and tell your browsers to use it, and you&#8217;re set.  Each browser is a little different, but most (if not all) support PAC files:</p>
<ul>
<li><strong>Safari</strong>: System Preferences -&gt; Network -&gt; Advanced&#8230; -&gt; Proxies -&gt; Automatic Proxy Configuration</li>
<li><strong>Firefox</strong>: Preferences -&gt; Advanced -&gt; Network -&gt; &#8220;Configure how Firefox connects to the Internet&#8221; -&gt; Automatic proxy configuration URL</li>
<li><strong>MSIE</strong>: Tools -&gt; Internet Options -&gt; Connections -&gt; LAN Settings -&gt; Use automatic configuration script</li>
<li><strong>Chrome</strong>: Uses Safari/Internet Explorer settings</li>
<li><strong>Opera</strong>: Preferences -&gt; Advanced -&gt; Network -&gt; Use automatic proxy configuration</li>
</ul>
<p>Now, when you go to <strong>http://mynextawesomeidea.localhost</strong> your system will automatically attempt to load <strong>/path/to/vhosts/mynextawesomeidea/public</strong>.  Any time you want to start a new project, just create the directory and go!</p>
<p><strong>A couple notes:</strong> this technique messes with a few environmental variables.  Apache seems to get confused about your DOCUMENT_ROOT and REQUEST_URI.  Your document root is going to be your global document root, not the /path/to/vhosts/&#8230; directory, and your REQUEST_URI will include the hostname and protocol parts, not just the path and query parts.  Another side effect is that you need to set your RewriteBase to / if you&#8217;re using mode_rewrite.</p>
<div class="su-linkbox" id="post-768-linkbox"><div class="su-linkbox-label">Link to this post!</div><div class="su-linkbox-field"><input type="text" value="&lt;a href=&quot;http://cmorrell.com/webdev/automatic-virtual-hosts-w-proxy-auto-config-768&quot;&gt;Automatic Virtual Hosts w/ Proxy Auto-Config&lt;/a&gt;" onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" /></div></div>]]></content:encoded>
			<wfw:commentRss>http://cmorrell.com/webdev/automatic-virtual-hosts-w-proxy-auto-config-768/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Review: Zend Framework 1.8 Web Application Development</title>
		<link>http://cmorrell.com/webdev/zf/review-1-8-web-application-development-760</link>
		<comments>http://cmorrell.com/webdev/zf/review-1-8-web-application-development-760#comments</comments>
		<pubDate>Wed, 24 Mar 2010 15:02:26 +0000</pubDate>
		<dc:creator>Chris M.</dc:creator>
				<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[wishlist]]></category>

		<guid isPermaLink="false">http://cmorrell.com/?p=760</guid>
		<description><![CDATA[At the beginning of February PACKT Publishing sent me a copy of Zend Framework 1.8 Web Application Development by Keith Pope and asked me to post a review.  Unfortunately a bunch of stuff came up, so it wasn&#8217;t until this &#8230; <a href="http://cmorrell.com/webdev/zf/review-1-8-web-application-development-760">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>At the beginning of February <a href="http://www.packtpub.com/" target="_blank">PACKT Publishing</a> sent me a copy of <em><a href="http://www.amazon.com/gp/product/1847194222?ie=UTF8&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;tag=inxilcom-20&amp;creativeASIN=1847194222">Zend Framework 1.8 Web Application Development</a></em> by Keith Pope and asked me to post a review.  Unfortunately a bunch of stuff came up, so it wasn&#8217;t until this last week that I got a chance to really look it over.  Here are some of my thoughts.</p>
<p><span id="more-760"></span></p>
<p>The book is structured in two parts.  The first two chapters cover the basic setup of the Zend Framework (ZF) and, more specifically, a look at its Model-View-Controller (MVC) implementation.  Almost all of the book from there on out focuses on building a real-world ecommerce application using ZF.  I tend to be a learning-by-doing type of person, which I think tends to be true of many programmers, so I think this is a pretty good way to lay out a book.</p>
<p>Much of the book focuses on Models, and how to use various ZF components to implement your domain logic.  Most people agree nowadays that you should have fat models and skinny controllers (in that your controllers should really just have enough code to facilitate your models doing the work), and Keith Pope&#8217;s focus on models really hits this home in the book.  The topics of user accounts, the shopping cart and the catalog are all addressed in this light, while still bringing up topics like forms, controllers, views, action helpers, etc.</p>
<p>In general, the book focuses on best practices, which I think is really important for new ZF developers.  Because one of the guiding principals of the Zend Framework is that it gives you freedom to implement things however you like and use only the components you want, it can be hard for people just getting started to get a sense of how they should use certain components, and particularly how everything falls together in a &#8220;typical&#8221; MVC application.   Following along with the development of the storefront application in this book is a great way to see how those components often are used together.</p>
<p>That said, there are ways in which the code in this book is outdated or less-than-ideal.  As with anything that moves as fast as the Zend Framework has been moving, it&#8217;s hard to keep up with the latest tricks and best practices (and in some places it feels like they skipped on editing to try to publish the book before it got too outdated—there are plenty of minor code inconsistencies and typos throughout).  This book is a good place to get started, but keep in mind that the Zend Framework is already at 1.10, with 2.0 on the horizon, so anything that&#8217;s not the <a href="http://framework.zend.com/manual/en/" target="_blank">Zend Framework Official Documentation</a> is in danger of being out of date at any moment.</p>
<p>Also, keep in mind that there&#8217;s already a lot of good information out there, so if you don&#8217;t mind finding it yourself, you might not need a book.  In fact, I found that most of the code in the authorization chapter was almost a direct copy of <a href="http://weierophinney.net/matthew/archives/201-Applying-ACLs-to-Models.html" target="_blank">Matthew Weier O&#8217;Phinney&#8217;s blog post on Applying ACL&#8217;s to Models</a>.  If you read blogs like Matthew&#8217;s (who is the project lead for ZF, and a fantastic resource) and spend time on <a href="http://zftalk.com/" target="_blank">#zftalk</a> you can figure most things out on your own (<a href="http://site.svn.dasprids.de/trunk/" target="_blank">Ben Scholzen&#8217;s demo application</a> is another good starting point).  The information may be a little scattered, but it&#8217;s out there.</p>
<p>In the end, I think that this book would be a really helpful resource to someone who&#8217;s just getting started with MVC architecture and other design patterns in PHP.  It also is a good way to see most of the Zend Framework best practices put to use in one place.  On the other hand, if you want the latest information available and are willing to work for it, everything you need is probably online and free.</p>
<p>Some resources that might be helpful to new ZF developers:</p>
<ul>
<li><a href="http://devzone.zend.com/tag/Zend%20Framework" target="_blank">Zend DevZone</a></li>
<li><a href="http://stackoverflow.com/questions/tagged/zend-framework" target="_blank">Questions tagged w/ Zend Framework on Stack Overflow</a></li>
<li><a href="http://zftalk.com/" target="_blank">#zftalk</a></li>
<li><a href="http://www.zendframeworkinaction.com/" target="_blank">Zend Framework in Action Blog</a></li>
<li><a href="http://weierophinney.net/matthew/" target="_blank">Matthew Weier O&#8217;Phinney&#8217;s Blog</a></li>
<li><a href="http://www.rmauger.co.uk/" target="_blank">Ryan Mauger&#8217;s Blog</a></li>
<li><a href="http://www.dasprids.de/" target="_blank">Ben Scholzen&#8217;s Blog</a></li>
</ul>
<div class="su-linkbox" id="post-760-linkbox"><div class="su-linkbox-label">Link to this post!</div><div class="su-linkbox-field"><input type="text" value="&lt;a href=&quot;http://cmorrell.com/webdev/zf/review-1-8-web-application-development-760&quot;&gt;Review: Zend Framework 1.8 Web Application Development&lt;/a&gt;" onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" /></div></div>]]></content:encoded>
			<wfw:commentRss>http://cmorrell.com/webdev/zf/review-1-8-web-application-development-760/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Zend Framework Bash Completion Script</title>
		<link>http://cmorrell.com/webdev/zf/bash-completion-script-751</link>
		<comments>http://cmorrell.com/webdev/zf/bash-completion-script-751#comments</comments>
		<pubDate>Sat, 20 Mar 2010 15:05:11 +0000</pubDate>
		<dc:creator>Chris M.</dc:creator>
				<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[wishlist]]></category>

		<guid isPermaLink="false">http://cmorrell.com/?p=751</guid>
		<description><![CDATA[If you use the Zend Framework CLI interface much you probably find yourself expecting tab-completion to work.  Well, with this bash completion script it will.  Just add the following line to your .bashrc or .bash_profile: source path/to/zf.bash Next time you &#8230; <a href="http://cmorrell.com/webdev/zf/bash-completion-script-751">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>If you use the Zend Framework CLI interface much you probably find yourself expecting tab-completion to work.  Well, with this bash completion script it will.  Just add the following line to your .bashrc or .bash_profile:</p>
<p><code>source path/to/zf.bash</code></p>
<p>Next time you load the terminal, you can type &#8220;zf c&#8221; and hit TAB twice to see a list of available commands (change, configure and create&#8221; or type &#8220;zf cr&#8221; and hit TAB to have &#8220;create&#8221; automatically inserted for you.  The script works for both action names and provider names (but not for anything past that).  Eventually I want the script to dynamically load the available commands (so that it works with custom providers and future versions of ZF without updates) but I couldn&#8217;t get that working for this version so I just hard coded them.</p>
<p>There&#8217;s also a version that completes commands from the <a href="http://cmorrell.com/open-source/galahad-framework-extension">Galahad Framework Extension</a> if you&#8217;re testing that out…</p>
<a href="http://cmorrell.com/downloads/5" title="Version 1.10.2, Downloaded 1827 times">Zend Framework CLI Bash Completion Script [1.71 kB]</a>
<p>Enjoy!</p>
<div class="su-linkbox" id="post-751-linkbox"><div class="su-linkbox-label">Link to this post!</div><div class="su-linkbox-field"><input type="text" value="&lt;a href=&quot;http://cmorrell.com/webdev/zf/bash-completion-script-751&quot;&gt;Zend Framework Bash Completion Script&lt;/a&gt;" onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" /></div></div>]]></content:encoded>
			<wfw:commentRss>http://cmorrell.com/webdev/zf/bash-completion-script-751/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Namespacing ACL resources &amp; Galahad_Acl</title>
		<link>http://cmorrell.com/webdev/zf/namespacing-acl-resources-galahad-acl-737</link>
		<comments>http://cmorrell.com/webdev/zf/namespacing-acl-resources-galahad-acl-737#comments</comments>
		<pubDate>Wed, 17 Mar 2010 16:04:25 +0000</pubDate>
		<dc:creator>Chris M.</dc:creator>
				<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[galahad-fe]]></category>
		<category><![CDATA[wishlist]]></category>

		<guid isPermaLink="false">http://cmorrell.com/?p=737</guid>
		<description><![CDATA[In most of my applications I like to handle authorization (querying the ACL) in one (or more) of three ways: Authorize access to a model&#8217;s method Authorize access to a controller action Authorize access to an arbitrary &#8220;permission&#8221; In general &#8230; <a href="http://cmorrell.com/webdev/zf/namespacing-acl-resources-galahad-acl-737">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In most of my applications I like to handle authorization (querying the ACL) in one (or more) of three ways:</p>
<ul>
<li>Authorize access to a model&#8217;s method</li>
<li>Authorize access to a controller action</li>
<li>Authorize access to an arbitrary &#8220;permission&#8221;</li>
</ul>
<p>In general I find it&#8217;s best to keep authorization within the domain (querying the ACL within my models when they&#8217;re accessed) as this provides the most consistent behavior.  For example, if I eventually add a REST API to my application I don&#8217;t have to duplicate all my authorization logic in the new REST controllers.  When the application calls something like <code>Default_Model_Post::save()</code> it either saves or throws an ACL exception, no matter where it was called from.  This is great in that it saves me from having to duplicate code and keeps my system more secure.</p>
<p>On the other hand, there are times when it&#8217;s just a lot easier to handle authorization in the controller.  For example, if guests should never access my &#8220;Admin&#8221; module, it doesn&#8217;t make sense to ever let them access /admin/ URLs.  Also, if you&#8217;re using Zend_Navigation, having ACL resources that match controller actions lets you utilize its ACL integration.</p>
<p>If you&#8217;re ever going to mix these two techniques, you&#8217;ll eventually bump into the case where a model and a controller share the same name.  What if you need to set permissions on a &#8220;user&#8221; controller and different permissions on a &#8220;user&#8221; model?  This is where namespacing comes into play.  As suggested by the <a href="http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.navigation.setup" target="_blank">Zend Framework manual</a>, I always name my controller action resources in the format <code>mvc:module.controller.action</code>.  I name my model resources similarly, in the format <code>model:module.modelName.methodName</code>.  In both theses cases, &#8220;mvc&#8221; and &#8220;model&#8221; are the namespace, and everything following the colon is the actual resource name.  Now I can refer to my &#8220;admin&#8221; module as <code>mvc:admin</code> and the models within my admin module as <code>model:admin</code>.</p>
<p>This is where things get interesting.  If you set up your ACL chains correctly, you can set permissions on whole modules or models and have those rules cascade to their child controllers or methods.  For example, say you set up your ACL as follows:</p>
<pre class="brush: php; title: ; notranslate">
$acl = new Zend_Acl();
$acl-&gt;addResource('mvc:');
$acl-&gt;addResource('mvc:admin', 'mvc:');
$acl-&gt;addResource('mvc:admin.user', 'mvc:admin');
$acl-&gt;addResource('mvc:admin.user.create', 'mvc:admin.user');

$acl-&gt;addRole('guest');
$acl-&gt;addRole('admin', 'guest');

$acl-&gt;deny();
$acl-&gt;allow('admin', 'mvc:admin');
</pre>
<p>Now if a user with the role &#8220;admin&#8221; tries to access the resource &#8220;mvc:admin.user.create&#8221; (http://basename/admin/user/create) they will be allowed, but a user with the role &#8220;guest&#8221; will not.  Using this technique gives you as much granularity as you need in your ACL, but at the same time lets you set broad permissions where appropriate.</p>
<p>This is where <code>Galahad_Acl</code> comes into play.  Setting up all these resources can be tedious, as is checking permissions in each controller.  <code>Galahad_Acl</code> in conjunction with <code>Galahad_Model_Entity</code> and <code>Galahad_Controller_Plugin_Acl</code> automate everything but the actual permissions that are specific to your application.</p>
<p><span id="more-737"></span></p>
<p>By default, whenever <code>Galahad_Acl</code> has a role added to it in the format &#8220;namespace:resource.subResourse&#8221; (etc) it automatically adds the resources up the chain.  For example, if I add &#8220;mvc:default.index.index&#8221; to a Galahad_Acl object, it would add the following resources to the ACL:</p>
<ul>
<li>mvc:</li>
<li>mvc:default (parent = &#8220;mvc:&#8221;)</li>
<li>mvc:default.index (parent = &#8220;mvc:default&#8221;)</li>
<li>mvc:default.index.index (parent = &#8220;mvc:default.index&#8221;)</li>
</ul>
<p><code>Galahad_Controller_Plugin_Acl</code> takes this a step further by automatically adding any controller action that&#8217;s dispatched to the ACL and then checking against the ACL.  This means that with the following ACL:</p>
<pre class="brush: php; title: ; notranslate">
$acl = new Galahad_Acl();
$acl-&gt;addRole('guest');
$acl-&gt;addRole('staff', 'guest');
$acl-&gt;addRole('admin', 'staff');
$acl-&gt;addResource('mvc:blog.entry.view');
$acl-&gt;deny();
$acl-&gt;allow('admin', 'mvc:');
$acl-&gt;allow('staff', 'mvc:blog');
$acl-&gt;allow('guest', 'mvc:blog.entry.view');
</pre>
<p>The following would be true:</p>
<ul>
<li>Role &#8220;admin&#8221; would be allowed access to any URL (&#8220;admin&#8221; is allowed access to &#8220;mvc:&#8221;)</li>
<li>Role &#8220;staff&#8221; would be allowed access to /blog/entry/edit even though permissions weren&#8217;t explicitly set for the resource &#8220;mvc:blog.entry.edit&#8221; (because &#8220;staff&#8221; is allowed to access &#8220;mvc:blog&#8221;)</li>
<li>Role &#8220;guest&#8221; would be allowed to view /blog/entry/view but no other portion of the blog (&#8220;guest&#8221; is allowed access to the specific resource &#8220;mvc:blog.entry.view&#8221;)</li>
</ul>
<p><code>Galahad_Model_Entity</code> works similarly.  By default each entity adds itself to the ACL in the format &#8220;model:module.modelName&#8221; so that the model <code>Default_Model_User</code> has the resource ID &#8220;model:default.user&#8221;.  Each model has a method called <code>_initAcl</code> which lets you manage permissions on a per-model basis.  This is better demonstrated in code:</p>
<pre class="brush: php; title: ; notranslate">
class Default_Model_Post extends Galahad_Model_Entity
{
    protected function _initAcl($acl)
    {
        // Deny permissions to anything on this model unless explicitly allowed
        // We don't have to add &quot;model:default.post&quot; because Galahad_Model_Entity
        // automatically does that for us
        $acl-&gt;deny(null, $this);

        // Allow guests to fetch the content of posts
        $acl-&gt;allow('guest', $this, 'fetch')

        // Allow admins to save changes to posts
        $acl-&gt;allow('admin', $this, 'save')
    }

    public function save()
    {
        if (!$this-&gt;getAcl()-&gt;isAllowed($this-&gt;getRole(), $this, 'save')) {
            throw new Galahad_Acl_Exception('Current user is not allowed to save posts');
        }

        $dataMapper = $this-&gt;getDataMapper();
        return $dataMapper-&gt;save($this);
    }
}
</pre>
<p>So, as you can see, the model denies access to itself unless explicitly allowed, and then allows access to certain methods for certain roles.</p>
<p>All three of these classes are in their early stages of development, but I&#8217;d love some feedback on the ideas/suggestions on how to make them better.</p>
<p>Check out the code on GitHub:</p>
<ul>
<li><a href="http://github.com/inxilpro/Galahad-FE/blob/master/library/Galahad/Acl.php" target="_blank">Galahad_Acl</a></li>
<li><a href="http://github.com/inxilpro/Galahad-FE/blob/master/library/Galahad/Controller/Plugin/Acl.php" target="_blank">Galahad_Controller_Plugin_Acl</a></li>
<li><a href="http://github.com/inxilpro/Galahad-FE/blob/master/library/Galahad/Model/Entity.php" target="_blank">Galahad_Model_Entity</a></li>
</ul>
<p>Also, for more information about the <code>Galahad_Model</code> system, check out my previous post on <a href="http://cmorrell.com/web-development/more-php-modelling-383">modeling in the Zend Framework</a>.</p>
<div class="su-linkbox" id="post-737-linkbox"><div class="su-linkbox-label">Link to this post!</div><div class="su-linkbox-field"><input type="text" value="&lt;a href=&quot;http://cmorrell.com/webdev/zf/namespacing-acl-resources-galahad-acl-737&quot;&gt;Namespacing ACL resources &amp; Galahad_Acl&lt;/a&gt;" onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" /></div></div>]]></content:encoded>
			<wfw:commentRss>http://cmorrell.com/webdev/zf/namespacing-acl-resources-galahad-acl-737/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Zend Framework URI validator &amp; filter</title>
		<link>http://cmorrell.com/webdev/zf/validate-filter-url-728</link>
		<comments>http://cmorrell.com/webdev/zf/validate-filter-url-728#comments</comments>
		<pubDate>Fri, 12 Mar 2010 19:06:53 +0000</pubDate>
		<dc:creator>Chris M.</dc:creator>
				<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[wishlist]]></category>

		<guid isPermaLink="false">http://cmorrell.com/?p=728</guid>
		<description><![CDATA[For the last couple of months I&#8217;ve been incorporating portions of applications I&#8217;m working on into my Galahad Framework Extension project.  Right now it&#8217;s not at a point where I&#8217;d feel comfortable promoting it (you can check out the project &#8230; <a href="http://cmorrell.com/webdev/zf/validate-filter-url-728">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>For the last couple of months I&#8217;ve been incorporating portions of applications I&#8217;m working on into my Galahad Framework Extension project.  Right now it&#8217;s not at a point where I&#8217;d feel comfortable promoting it (you can <a title="Galahad Framework Extension" href="http://bit.ly/d3ULiy" target="_blank">check out the project on GitHub</a> if you want), but there are portions that are pretty solid that might be useful to others right now.  Two such portions are <code>Galahad_Validate_Uri</code> and <code>Galahad_Filter_PrependHttp</code> which are both very useful for processing forms with URL fields.</p>
<p><span id="more-728"></span></p>
<p>Recently I was building a form that contained a URL field, and after browsing the <a href="http://framework.zend.com/manual/en/zend.validate.html" target="_blank">Zend_Validate docs</a>, I was surprised not to find a <code>Zend_Validate_Uri</code> component.  Luckily, <code>Zend_Uri</code> already validates URIs, so it was just a matter of writing a wrapper that followed the Zend_Validate APIs.  Basic usage:</p>
<pre class="brush: php; title: ; notranslate">
$validator = new Galahad_Validate_Uri();
$validator-&gt;isValid('http://www.google.com/');
</pre>
<p>Obviously this would be much more useful when combined with <code>Zend_Form</code> or some more extensive validation chains, but you get the point.</p>
<p>Grab <a href="http://bit.ly/cFB0li" target="_blank">Galahad_Validate_Uri</a> from GitHub.</p>
<p>The second issue I often deal with is people forgetting (or not knowing) to include http:// in the URLs that they submit.  Rather than solve this at the controller-level, I decided this was a common enough problem to build a Zend_Filter component for.  Basic usage:</p>
<pre class="brush: php; title: ; notranslate">
$filter = new Galahad_Filter_PrependHttp(array(
    'allowedSchemes' =&gt; array('http://', 'https://', 'mailto:'),
    'checkUri' =&gt; true,
));
echo $filter-&gt;filter('google.com'); // Prints 'http://google.com'
</pre>
<p>This filter takes any string and prepends &#8220;http://&#8221; to it if it doesn&#8217;t already contain an allowed scheme (more on that below).  By default it allows &#8220;http://&#8221;, &#8220;https://&#8221; and &#8220;mailto:&#8221; schemes, but you could set this to anything (say you want to allow &#8220;itms://&#8221; [iTunes] links) by setting the &#8216;allowedSchemes&#8217; option.  It also (optionally) checks if the resulting URI is valid, and only applies the filter if it is (effectively only prepending &#8220;http://&#8221; to otherwise valid URIs).  Remember, though, that &#8220;http://something&#8221; is technically a valid URI, so that will be accepted.  In the future I hope to add additional options to limit to URLs that follow certain standards.</p>
<p>Grab <a href="http://bit.ly/csqLWK" target="_blank">Galahad_Filter_PrependHttp</a> from GitHub.</p>
<p><strong>Update</strong>: I&#8217;ve submitted Zend_Filter_PrependHttp to the Zend Framework wiki for comments.  <a href="http://framework.zend.com/wiki/display/ZFPROP/Zend_Filter_PrependHttp+-+Chris+Morrell" target="_blank">Check it out</a> and let me know if you think there&#8217;s anything I should change (I&#8217;ve posted a few ideas already).</p>
<p>The validator and filter work well together with <code>Zend_Form</code> to create URL form elements:</p>
<pre class="brush: php; title: ; notranslate">
$this-&gt;addElement('text', 'my_url', array(
    'label' =&gt; 'URL:',
    'filters' =&gt; array('StringTrim', 'StringToLower', new Galahad_Filter_PrependHttp()),
    'validators' =&gt; array(new Galahad_Validate_Uri()),
));
</pre>
<p>The form element generated by that code will produce fairly normalized, valid URIs.</p>
<div class="su-linkbox" id="post-728-linkbox"><div class="su-linkbox-label">Link to this post!</div><div class="su-linkbox-field"><input type="text" value="&lt;a href=&quot;http://cmorrell.com/webdev/zf/validate-filter-url-728&quot;&gt;Zend Framework URI validator &amp; filter&lt;/a&gt;" onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" /></div></div>]]></content:encoded>
			<wfw:commentRss>http://cmorrell.com/webdev/zf/validate-filter-url-728/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>More PHP Modeling (w/ video demo)</title>
		<link>http://cmorrell.com/webdev/more-php-modelling-383</link>
		<comments>http://cmorrell.com/webdev/more-php-modelling-383#comments</comments>
		<pubDate>Fri, 04 Dec 2009 17:49:26 +0000</pubDate>
		<dc:creator>Chris M.</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[wishlist]]></category>

		<guid isPermaLink="false">http://cmorrell.com/?p=383</guid>
		<description><![CDATA[[Updated with follow-up video] About a month ago I posted some ideas about PHP modeling in the Zend Framework and requested feedback. After a month of on-and-off discussions through this website and #zftalk I decided to sit down and implement &#8230; <a href="http://cmorrell.com/webdev/more-php-modelling-383">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong>[Updated with follow-up video]</strong></p>
<p>About a month ago I posted some ideas about <a href="http://cmorrell.com/web-development/php-modeling-in-zend-framework-360">PHP modeling in the Zend Framework</a> and requested feedback.  After a month of on-and-off discussions through this website and <a href="http://zftalk.com/">#zftalk</a> I decided to sit down and implement things a little more.<br />
<span id="more-383"></span><br />
I now have some working base classes that <a href="http://github.com/inxilpro/Galahad-FE">can be found on GitHub</a>.  Right now I&#8217;m still thinking things out, so there&#8217;s no guarantee that&#8217;s the structure I&#8217;m going to finish with, but it&#8217;s what I&#8217;m playing with right now.  So far I&#8217;ve dropped the DAO interface and the Galahad_Service parent class all together (since both are going to be pretty unique to your application).  What&#8217;s left is mostly the Entity class and the DataMapper class (as well as a very generic Collection class).</p>
<p>I&#8217;ve also started to write some tooling for my modeling system, based on <a href="http://framework.zend.com/manual/en/zend.tool.framework.html">Zend_Tool</a>.  Right now it&#8217;s generating the model itself, a DAO based on <a href="http://framework.zend.com/manual/en/zend.db.table.html">Zend_Db_Table</a> and a <a href="http://framework.zend.com/manual/en/zend.form.html">Zend_Form</a> (see <a href="http://weierophinney.net/matthew/archives/200-Using-Zend_Form-in-Your-Models.html">Matthew Weier O&#8217;Phinney&#8217;s post about using forms in your models</a> for my reasoning there).  It doesn&#8217;t generate the DataMapper yet, but that&#8217;s just a matter of writing the code…</p>
<p>Again, I&#8217;d love some feedback on the direction this is going.  Check out the video below and then let me know.  Comment below, email me at <a href="http://mailhide.recaptcha.net/d?k=01t3MHtCNlY1OI8TgogO8VwQ==&amp;c=3NSszgQSWON_Ovzh0YWmlyKF776ZaMWSTct2mtNMEaM=" onclick="window.open('http://mailhide.recaptcha.net/d?k=01t3MHtCNlY1OI8TgogO8VwQ==&amp;c=3NSszgQSWON_Ovzh0YWmlyKF776ZaMWSTct2mtNMEaM=', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;" title="Reveal this e-mail address">*****@cmorrell.com</a> or get in touch on Twitter: <a href="http://twitter.com/inxilpro">@inxilpro</a>.</p>
<p>[<a href="http://www.screencast.com/t/MTFlZDJiNW" target="_blank">View full size</a>, or watch below]</p>
<p><object width="405" height="229"><param name="movie" value="http://content.screencast.com/users/inxilpro/folders/Jing/media/33a696b5-cc1f-4f15-af43-d6fb0e2b5fac/jingh264player.swf"></param><param name="quality" value="high"></param><param name="bgcolor" value="#FFFFFF"></param><param name="flashVars" value="thumb=http://content.screencast.com/users/inxilpro/folders/Jing/media/33a696b5-cc1f-4f15-af43-d6fb0e2b5fac/FirstFrame.jpg&#038;containerwidth=405&#038;containerheight=229&#038;content=http://content.screencast.com/users/inxilpro/folders/Jing/media/33a696b5-cc1f-4f15-af43-d6fb0e2b5fac/00000032.mp4"></param><param name="allowFullScreen" value="true"></param><param name="scale" value="showall"></param><param name="allowScriptAccess" value="always"></param><param name="base" value="http://content.screencast.com/users/inxilpro/folders/Jing/media/33a696b5-cc1f-4f15-af43-d6fb0e2b5fac/"></param>  <embed src="http://content.screencast.com/users/inxilpro/folders/Jing/media/33a696b5-cc1f-4f15-af43-d6fb0e2b5fac/jingh264player.swf" quality="high" bgcolor="#FFFFFF" width="405" height="229" type="application/x-shockwave-flash" allowScriptAccess="always" flashVars="thumb=http://content.screencast.com/users/inxilpro/folders/Jing/media/33a696b5-cc1f-4f15-af43-d6fb0e2b5fac/FirstFrame.jpg&#038;containerwidth=405&#038;containerheight=229&#038;content=http://content.screencast.com/users/inxilpro/folders/Jing/media/33a696b5-cc1f-4f15-af43-d6fb0e2b5fac/00000032.mp4" allowFullScreen="true" base="http://content.screencast.com/users/inxilpro/folders/Jing/media/33a696b5-cc1f-4f15-af43-d6fb0e2b5fac/" scale="showall"></embed></object></p>
<p>Follow-up Video (demo of a lot more code):</p>
<p><object width="320" height="265"><param name="movie" value="http://www.youtube.com/v/oABFXO9WV6w&#038;hl=en_US&#038;fs=1&#038;rel=0&#038;color1=0x5d1719&#038;color2=0xcd311b"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/oABFXO9WV6w&#038;hl=en_US&#038;fs=1&#038;rel=0&#038;color1=0x5d1719&#038;color2=0xcd311b" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="320" height="265"></embed></object></p>
<div class="su-linkbox" id="post-383-linkbox"><div class="su-linkbox-label">Link to this post!</div><div class="su-linkbox-field"><input type="text" value="&lt;a href=&quot;http://cmorrell.com/webdev/more-php-modelling-383&quot;&gt;More PHP Modeling (w/ video demo)&lt;/a&gt;" onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" /></div></div>]]></content:encoded>
			<wfw:commentRss>http://cmorrell.com/webdev/more-php-modelling-383/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
<enclosure url="http://content.screencast.com/users/inxilpro/folders/Jing/media/33a696b5-cc1f-4f15-af43-d6fb0e2b5fac/FirstFrame.jpg&amp;containerwidth=405&amp;containerheight=229&amp;content=http://content.screencast.com/users/inxilpro/folders/Jing/media/33a696b5-cc1f-4f15-af43-d6fb0e2b5fac/00000032.mp4" length="11368" type="video/mp4" />
		</item>
		<item>
		<title>Crazy idea…</title>
		<link>http://cmorrell.com/webdev/crazy-idea%e2%80%a6-378</link>
		<comments>http://cmorrell.com/webdev/crazy-idea%e2%80%a6-378#comments</comments>
		<pubDate>Mon, 23 Nov 2009 21:35:38 +0000</pubDate>
		<dc:creator>Chris M.</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://cmorrell.com/?p=378</guid>
		<description><![CDATA[I&#8217;ve been toying with the idea of using my cache as a data store for a project where the data doesn&#8217;t need to be updated very often.  Basically, I&#8217;d write out plain XHTML documents and then parse the data using &#8230; <a href="http://cmorrell.com/webdev/crazy-idea%e2%80%a6-378">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been toying with the idea of using my cache as a data store for a project where the data doesn&#8217;t need to be updated very often.  Basically, I&#8217;d write out plain XHTML documents and then parse the data using XPath when needed.  But that&#8217;s a different story.  Once I decided to give my idea a try, I started thinking about how to store authentication information.  The application doesn&#8217;t store any private information, so authentication is only needed to prove that you are authorized to edit the information.  So why not store the authentication information publicly as well (as an HTML comment at the top of the file)?  Here&#8217;s what I was thinking, in pseudo code:</p>
<pre>
identity = base64(encrypt_rijndael256([
	sha512_hmac(username, appUsernameSecret),
	sha512_hmac(password, appPasswordSecret)
], appSecret))
</pre>
<p>This would produce an base64 representation of an encrypted array of hashes.  Basically, the system would produce two hashes using HMAC and two separate secret keys (one for the username hash and one for the password hash).  It would store that data in a way that it could later retrieve it (in my case a serialized array) and then encrypt the whole thing with a third key (the base64 is just so it could easily be represented by an ASCII string).  That way there are multiple points of failure.  An attacker would have to know all three keys just to get at the hashes, but then that&#8217;s all they&#8217;d have.  They&#8217;d still need to brute force both the username and password separately.  It seems to me that this would be pretty darn secure.  Clearly not good enough for a bank, but certainly fine for a web app that would have very few negative consequences if it were broken into.</p>
<p>I would love feedback from someone who know&#8217;s what they&#8217;re talking about <img src='http://cdn1.cmorrell.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   Below is some working PHP code to illustrate my point:</p>
<p><span id="more-378"></span></p>
<pre class="brush: php; title: ; notranslate">
class PublicAuth
{
    private $_secret;
    private $_usernameSecret;
    private $_passwordSecret;

    private $_td = null;
    private $_iv = null;

    public function __construct($secret, $usernameSecret, $passwordSecret)
    {
        $this-&gt;_secret = $secret;
        $this-&gt;_usernameSecret = $usernameSecret;
        $this-&gt;_passwordSecret = $passwordSecret;
    }

    public function generateIdentifier($username, $password, $algorithm = 'sha512')
    {
        return $this-&gt;_encrypt(serialize(array(
            hash_hmac($algorithm, $username, $this-&gt;_usernameSecret, true),
            hash_hmac($algorithm, $password, $this-&gt;_passwordSecret, true),
        )));
    }

    public function verifyIdentity($identifier, $username, $password, $algorithm = 'sha512')
    {
        $identifier = unserialize($this-&gt;_decrypt($identifier));
        return (hash_hmac($algorithm, $username, $this-&gt;_usernameSecret, true) == $identifier[0]
            &amp;amp;&amp;amp; hash_hmac($algorithm, $password, $this-&gt;_passwordSecret, true) == $identifier[1]);
    }

    private function _encrypt($string)
    {
        $this-&gt;_initMcrypt();
        return base64_encode(mcrypt_generic($this-&gt;_td, $string));
    }

    private function _decrypt($string)
    {
        $this-&gt;_initMcrypt();
        return mdecrypt_generic($this-&gt;_td, base64_decode($string));
    }

    private function _initMcrypt($algorithm = 'rijndael-256')
    {
        if (null == $this-&gt;_td || null == $this-&gt;_iv) {
            $this-&gt;_td = mcrypt_module_open($algorithm, '', 'ecb', '');
            $this-&gt;_iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($this-&gt;_td), MCRYPT_RAND);
        }

        mcrypt_generic_init($this-&gt;_td, $this-&gt;_secret, $this-&gt;_iv);
    }
}
</pre>
<p>And here&#8217;s some sample usage:</p>
<pre class="brush: php; title: ; notranslate">
$pa = new PublicAuth('a', 'b', 'c');
echo $pa-&gt;generateIdentifier('user', 'pass');
</pre>
<p>Which would print out:</p>
<pre>NLgAYjlGbmJA2Wdcgwntm4ixhHHCiZBA6TvgrVMgEOBEjZQJ0tHgAlw7931p2S6KRtfCkLjrsA2DBilcgBX/pPPXFgyAx3g0/CKMcjdU8DKn3/9M2aIZHOrdi/G68C0oxVe6pDlWvVwvofpJnu9RxMbFN49x1uVgBuHTjKagpD6y83fm+hX4G+CoPRcHM5PUq/nJ1iwtZipRtno8TllO6A==</pre>
<p>Then to verify the identity:</p>
<pre class="brush: php; title: ; notranslate">
$pa = new PublicAuth('a', 'b', 'c'); // Needs to be the same as when generated
var_export($pa-&gt;verifyIdentity($id, 'user', 'pass')); // $id contains the string above; returns TRUE
</pre>
<p>Thoughts?</p>
<div class="su-linkbox" id="post-378-linkbox"><div class="su-linkbox-label">Link to this post!</div><div class="su-linkbox-field"><input type="text" value="&lt;a href=&quot;http://cmorrell.com/webdev/crazy-idea%e2%80%a6-378&quot;&gt;Crazy idea…&lt;/a&gt;" onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" /></div></div>]]></content:encoded>
			<wfw:commentRss>http://cmorrell.com/webdev/crazy-idea%e2%80%a6-378/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced
Database Caching 17/68 queries in 1.827 seconds using disk: basic
Object Caching 1301/1442 objects using disk: basic
Content Delivery Network via cdn1.cmorrell.com

Served from: cmorrell.com @ 2012-02-09 16:22:11 -->
