
<?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>Drew C King &#187; Evolving Framework</title>
	<atom:link href="http://www.drewcking.com/category/evolving-framework/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.drewcking.com</link>
	<description>My projects, code snippets, and miscellaneous ideas</description>
	<lastBuildDate>Fri, 09 Jul 2010 17:55:29 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9-rare</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Comb Rewrite: A Quick Overview</title>
		<link>http://www.drewcking.com/2009/03/comb-rewrite-a-quick-overview/</link>
		<comments>http://www.drewcking.com/2009/03/comb-rewrite-a-quick-overview/#comments</comments>
		<pubDate>Sat, 14 Mar 2009 18:20:44 +0000</pubDate>
		<dc:creator>Drew</dc:creator>
				<category><![CDATA[Comb]]></category>
		<category><![CDATA[Evolving Framework]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.drewcking.com/?p=50</guid>
		<description><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 I&#8217;ve been using Comb, my experimental PHP framework, for a couple of super-secret projects over the past few months (on those sporadic occasions when I actually write code), and it&#8217;s been evolving pretty dramatically.  So much so that very little of the original code still exists.  I&#8217;m still calling it &#8220;Comb&#8221; though, because [...]]]></description>
			<content:encoded><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 <p>I&#8217;ve been using Comb, my experimental PHP framework, for a couple of super-secret projects over the past few months (on those sporadic occasions when I actually write code), and it&#8217;s been evolving pretty dramatically.  So much so that very little of the original code still exists.  I&#8217;m still calling it &#8220;Comb&#8221; though, because the underlying idea is still the same.  It&#8217;s too time consuming to describe the reasons why I changed each part, so suffice it to say the changes are essentially organizational. Instead I&#8217;ll just jump into explaining it from the ground up as it exists now. </p>
<p>To begin with, here&#8217;s the now-simplified Apache VirtualHost container that I&#8217;m using:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;VirtualHost *:80&gt;
    ServerName      example.com
    DocumentRoot    /vhosts/example.com/www
    ErrorDocument   404 /404.php
&nbsp;
    &lt;Directory &quot;/vhosts/example.com/www&quot;&gt;
        AllowOverride All
        php_value include_path &quot;.:/vhosts/example.com/www/lib:/vhosts/lib&quot;
        php_value auto_prepend_file /vhosts/example.com/www/comb.php
    &lt;/Directory&gt;
&lt;/VirtualHost&gt;</pre></td></tr></table></div>

<p>The first four lines should be pretty self-explanatory, but for the rest:</p>
<ol start="7">
<li>Allow the full use of .htaccess files, e.g., for rewrite rules, etc</li>
<li>Set PHP&#8217;s include_path to the current working dir (when parsing templates), the application&#8217;s lib dir (for app-specific classes), and the system lib dir (for shared classes)</li>
<li>Prepend <code>comb.php</code> in the document root to every requested PHP script.</li>
</ol>
<p>This Apache configuration ensures that every requested script will first run the site&#8217;s <code>comb.php</code> script, which is a very simple, application-agnostic bootstrap script, meaning it&#8217;s basically the same for every app that I build.  In fact I could just have one copy of it in a central directory and prepend it from there, but I&#8217;d lose some potential flexibility that way.  Though that could probably be coded around.  Anyway, here&#8217;s where things get interesting&#8230; <code>comb.php</code> looks like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
    <span style="color: #b1b100;">require</span> <span style="color: #0000ff;">'/www/include/load.php'</span><span style="color: #339933;">;</span>
    spl_autoload_register<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'load'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$comb</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> util_comb<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$comb</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">run</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$comb</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">send</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>My standard autoloader is pretty simplistic; it just converts &#8220;util_comb&#8221; into &#8220;util/comb.php&#8221; and tries to include it based on the include_path set in the vhost container.</p>
<p>The <code>util_comb</code> class encapsulates all the crucial routing and response rendering logic.  The constructor parses the request URI into its segments and loops over them looking for any files called <code>prepend.php</code> and <code>append.php</code>.  If they exist, they&#8217;re added into an array that I refer to as the <em>inclusion list</em>.  To visualize this, imagine a request for <code>/user/profile.php?name=drew</code>.  The vhost will start by running <code>comb.php</code>, and the following scripts will get added to the inclusion list if they exist:</p>
<blockquote><p>
/prepend.php<br />
/user/prepend.php<br />
<b>/user/profile.php</b><br />
/user/append.php<br />
/append.php
</p></blockquote>
<p>&#8230;in that order.  The idea is to sort of mimic the way Apache finds and parses .htaccess files that are (possibly) in each subdirectory.</p>
<p>The next method that&#8217;s called, <code>$comb->run()</code>, simply loops over the inclusion list and <code>include()</code>s each one of them.</p>
<p>Finally, <code>$comb->send()</code> is called, in which the response is created and sent.  This is where template rendering or redirecting takes place.</p>
<p>My next few blog entries will go into the details of the inclusion list, how I&#8217;ve set up template rendering, and how to get clean/friendly URLs working.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.drewcking.com/2009/03/comb-rewrite-a-quick-overview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Camber &#8211; a minimalist LAMP framework</title>
		<link>http://www.drewcking.com/2007/06/camber-a-minimalist-lamp-framework/</link>
		<comments>http://www.drewcking.com/2007/06/camber-a-minimalist-lamp-framework/#comments</comments>
		<pubDate>Thu, 07 Jun 2007 23:29:45 +0000</pubDate>
		<dc:creator>Drew</dc:creator>
				<category><![CDATA[Camber]]></category>
		<category><![CDATA[Evolving Framework]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.drewcking.com/2007/06/08/camber-a-minimalist-lamp-framework/</guid>
		<description><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 Over the past few months I&#8217;ve been adding code to this previously unnamed LAMP framework, but I&#8217;ve honestly been reluctant to call it a framework.  That&#8217;s what it is though, so instead of constantly referring to it as &#8220;my little minimalist pseudo-framework&#8221;, I decided to give the thing a name.  I&#8217;ve been mulling [...]]]></description>
			<content:encoded><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 <p>Over the past few months I&#8217;ve been adding code to this previously unnamed LAMP framework, but I&#8217;ve honestly been reluctant to call it a framework.  That&#8217;s what it is though, so instead of constantly referring to it as &#8220;my little minimalist pseudo-framework&#8221;, I decided to give the thing a name.  I&#8217;ve been mulling it over for several months now, and finally settled on <b>Camber</b> as the name.  I wanted to be sure that it was easy enough to remember, but also meaningful to the overall goal of the project. According to <a href="http://www.google.com/search?q=define%3Acamber">Google</a>:</p>
<blockquote><p>
<b>Camber</b>: The curvature of a structural member for the purpose of offsetting the deflection when loads are applied.</p></blockquote>
<p>Camber is not a complex idea, nor is it difficult to implement where it&#8217;s needed. It&#8217;s used in many everyday load-bearing applications; the wheels of a car, the shape of skis and snowboards, the bottom of a bridge, the shape of a wing.  The performance of each of these is greatly enhanced &#8211; if not utterly dependent &#8211; on something as simple as the underlying negative curvature.  </p>
<p>Sounds like a pretty good description of a web application framework, eh?</p>
<p>Unfortunately, I&#8217;ve been really slack about keeping this here blog up to date with the actual code I&#8217;ve been writing.  I have a tendency to drone on and on about each concept of the system, so I think I need to take smaller bites.  One post per day maybe, with no more than 2 or 3 snippets of code.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.drewcking.com/2007/06/camber-a-minimalist-lamp-framework/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Evolving Framework, Step 4: Handle requests with a request handler</title>
		<link>http://www.drewcking.com/2007/04/evolving-framework-request-handler/</link>
		<comments>http://www.drewcking.com/2007/04/evolving-framework-request-handler/#comments</comments>
		<pubDate>Sun, 29 Apr 2007 03:04:49 +0000</pubDate>
		<dc:creator>Drew</dc:creator>
				<category><![CDATA[Evolving Framework]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.cholmon.com/2007/04/29/step-4-handle-requests-with-a-request-handler/</guid>
		<description><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 So, picking up from where I left off in Step 3, cleaning up the server-side, we&#8217;ve now got a simple HTML form that sends a clean request into the server, and a nice little Request class to make the incoming data easy to work with.  To jog your memory, the form looks like:


1
2
3
4
5
6
&#60;form action=&#34;/session&#34; [...]]]></description>
			<content:encoded><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 <p>So, picking up from where I left off in Step 3, <a href="/2007/01/30/evolving-framework-cleaning-up-the-server-side/">cleaning up the server-side</a>, we&#8217;ve now got a simple HTML form that sends a clean request into the server, and a nice little <code>Request</code> class to make the incoming data easy to work with.  To jog your memory, the form looks like:<br />
<span id="more-13"></span></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;form action=&quot;/session&quot; method=&quot;post&quot;&gt;
  &lt;input type=&quot;hidden&quot; name=&quot;method&quot; value=&quot;put&quot; /&gt;
  Username: &lt;input type=&quot;text&quot; name=&quot;username&quot; /&gt;&lt;br /&gt;  
  Password: &lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;&lt;br /&gt;  
  &lt;input type=&quot;submit&quot; value=&quot;Login...&quot; /&gt;  
&lt;/form&gt;</pre></td></tr></table></div>

<p>When the form gets submitted, <code>index.php</code> creates a new <code>Request</code> object to encapsulate all the request data.  But once the Request is all set up, then what?  My goal here is to log the user into their account, or if I read the HTTP request the way I intended it to be interpreted, I want to&#8230;</p>
<blockquote><p><em><u>Put</u> a <u>session</u> on the server with the specified <u>username</u> and <u>password</u></em>.</p></blockquote>
<p>Well, the most straightforward way to do this would be to just stick all the input-sanitizing, database-connecting, user-authenticating logic directly after the Request object is born, making <code>index.php</code> look something like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
    <span style="color: #b1b100;">include</span> <span style="color: #0000ff;">'Request.php'</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * create the request
     */</span>
    <span style="color: #000088;">$req</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Request<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * pull the necessary data out of the request
     * i.e., 
     *  username=drew&amp;password=qwerty
     *
     * In real life, error checking and validation would be a good idea here
     */</span>
    <span style="color: #000088;">$username</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$req</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">params</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'username'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$password</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$req</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">params</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/** 
     * Connect to the db and see if the username/password combo is valid
     * I like mysqli: http://www.php.net/mysqli
     */</span>
    <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> MySQLi<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'localhost'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'dbuser'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'securepassword'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'dbname'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$sql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'SELECT UserID FROM Users WHERE Username = ? AND Password = MD5(?)'</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$stmt</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">prepare</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sql</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$stmt</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">bind_param</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'ss'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$username</span><span style="color: #339933;">,</span> <span style="color: #000088;">$password</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$stmt</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$stmt</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">bind_result</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$userID</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$stmt</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">fetch</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$userID</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #990000;">die</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;access denied, try again.&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">else</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #990000;">die</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;access granted! userid: <span style="color: #006699; font-weight: bold;">$userid</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #000088;">$stmt</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Hopefully it is obvious to you that putting all that code smack in the middle of the site&#8217;s one-and-only <code>index.php</code> would suck really badly.  Afterall, <code>index.php</code> has to handle <em>every single request</em>.  The only reasonable way to go about this is to have some sort of dynamically loaded request-examining code.  I&#8217;ll have to decide on some standard way to look at every request, and depending on the method, path, and parameters, load up some request-specific logic on the fly.  Something to this affect:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
    <span style="color: #b1b100;">include</span> <span style="color: #0000ff;">'Request.php'</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">include</span> <span style="color: #0000ff;">'RequestHandler.php'</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$request</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Request<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Create this magical object that &quot;handles&quot; the given $request object
     */</span>
    <span style="color: #000088;">$handler</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> RequestHandler<span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Tell the RequestHandler to do the dirty work
     */</span>
    <span style="color: #000088;">$handler</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">run</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>This would get the clutter out of <code>index.php</code> and into the <code>RequestHandler</code> object.  Of course, the <code>RequestHandler</code> is a black box at this point, but the idea is to use that class in such a way as to load up and run the request-specific logic, i.e., form validation, database querying, and of course output.</p>
<p>Step 5 will consider what exactly the RequestHandler needs to do, and how we might need to modify our currently bare-bones <code>index.php</code> bootstrap.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.drewcking.com/2007/04/evolving-framework-request-handler/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Evolving Framework, Step 3: Cleaning up the server-side</title>
		<link>http://www.drewcking.com/2007/01/evolving-framework-cleaning-up-the-server-side/</link>
		<comments>http://www.drewcking.com/2007/01/evolving-framework-cleaning-up-the-server-side/#comments</comments>
		<pubDate>Tue, 30 Jan 2007 10:37:07 +0000</pubDate>
		<dc:creator>Drew</dc:creator>
				<category><![CDATA[Evolving Framework]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.cholmon.com/?p=9</guid>
		<description><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 Once I had my virtual host set up to route all requests into a single script, I then had to figure out what to do with each request.  I knew that the essential request information was available in the $_SERVER autoglobal, but I wanted a cleaner way of dealing with the request.  So [...]]]></description>
			<content:encoded><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 <p>Once I had my virtual host set up to route all requests into a single script, I then had to figure out what to do with each request.  I knew that the essential request information was available in the $_SERVER autoglobal, but I wanted a cleaner way of dealing with the request.  So I put together a very simple Request class, which I saved in the document root as <strong>Request.php</strong>:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> 
<span style="color: #000000; font-weight: bold;">class</span> Request 
<span style="color: #009900;">&#123;</span> 
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$method</span><span style="color: #339933;">;</span> 
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$url</span><span style="color: #339933;">;</span> 
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$parameters</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> 
    <span style="color: #009900;">&#123;</span> 
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">method</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_METHOD'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span> 
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">url</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'SCRIPT_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span> 
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">parameters</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_REQUEST</span><span style="color: #339933;">;</span> 
    <span style="color: #009900;">&#125;</span> 
<span style="color: #009900;">&#125;</span> 
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>I then altered <strong>index.php</strong> to contain the following:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
    <span style="color: #b1b100;">include</span> <span style="color: #0000ff;">'Request.php'</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$req</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Request<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>   
&nbsp;
    <span style="color: #990000;">echo</span> <span style="color: #0000ff;">&quot;Method: <span style="color: #006699; font-weight: bold;">{$req-&gt;method}</span> &lt;br /&gt;&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #990000;">echo</span> <span style="color: #0000ff;">&quot;URL: <span style="color: #006699; font-weight: bold;">{$req-&gt;url}</span> &lt;br /&gt;&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #990000;">echo</span> <span style="color: #0000ff;">&quot;Parameters: &lt;code&gt;&quot;</span> <span style="color: #339933;">.</span> <span style="color: #990000;">print_r</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$req</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">parameters</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;&lt;/code&gt;&quot;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p><span id="more-9"></span><br />
To give it a test run, I pointed my browser to <strong>http://dev.cholmon.com/some/fake/path?name=drew&amp;gender=male</strong> and it showed me:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">Method: GET
Path: /some/fake/path
Params:  
Array  
(  
    [name] =&gt; drew  
    [gender] =&gt; male 
)</pre></td></tr></table></div>

<p>This is exactly what I was expecting. So I decided to try it with my RESTful login form from Step 2. I saved that HTML code:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;form action=&quot;/session&quot; method=&quot;put&quot;&gt;
  Username &lt;input type=&quot;text&quot; name=&quot;username&quot; /&gt;  
  Password &lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;
  &lt;input type=&quot;submit&quot; value=&quot;Login...&quot; /&gt;  
&lt;/form&gt;</pre></td></tr></table></div>

<p>&#8230;into the document root as <strong>login.html</strong>, but then I remembered that Apache wasn&#8217;t going to serve that file properly because of my RewriteRules. I had a rule in the vhost container that let images, css, and js files get served up as-is, so I just added &#8220;html&#8221; as another file extension. In other words, this:</p>
<blockquote><p>RewriteRule     /\w+\.(css|js|gif|png|jpe?g)$ &#8211; [NC,L]</p></blockquote>
<p>Became this:</p>
<blockquote><p>RewriteRule     /\w+\.(html|css|js|gif|png|jpe?g)$ &#8211; [NC,L]</p></blockquote>
<p>I made the change and restarted Apache, then I hit <strong>http://dev.cholmon.com/login.html</strong> and got the little login form as expected. When I tried submitting the form, however, I noticed a slight problem. The page displayed everything properly except for the request method:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">Method: GET
Path: /session  
Params:  
Array  
(  
    [username] =&gt; drew  
    [password] =&gt; mypass  
)</pre></td></tr></table></div>

<p>Where did that GET come from? I specified &#8220;put&#8221; as the method in my form element, so how did that get translated into a &#8220;get&#8221;? I decided to try a few other tests; if PUT became GET, what would DELETE become? I changed <code>login.html</code> to use <code>method="delete"</code> in the form element, but I got the exact same result when I submitted the form. What about <code>method="omgwtf"</code>? No good, it displayed as GET again. What about just leaving the method attribute out of the form element altogether? You guessed it&#8230;GET. The only way I could make the thing show up any different is if I put <code>method="post"</code> in the form. So I came to the conclusion that my browser only knows how to send GET and POST requests. After a bit of googling, I also came to the conclusion that I am probably one of the last web developers to realize this little limitation.</p>
<p>GET and PUT are only the &#8220;RU&#8221; of CRUD though, and I want the whole thing.  So I had to figure out some way to force my request method through.  So I rigged up the form with the most obvious solution:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;form action=&quot;/session&quot; method=&quot;post&quot;&gt;
  &lt;input type=&quot;hidden&quot; name=&quot;method&quot; value=&quot;put&quot; /&gt;
  Username: &lt;input type=&quot;text&quot; name=&quot;username&quot; /&gt;&lt;br /&gt;  
  Password: &lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;&lt;br /&gt;  
  &lt;input type=&quot;submit&quot; value=&quot;Login...&quot; /&gt;  
&lt;/form&gt;</pre></td></tr></table></div>

<p>Basically the idea is to wrap any PUT or DELETE requests inside a POST request by specifying a hidden &#8220;method&#8221; parameter that effectively overrides the form&#8217;s &#8220;method&#8221; parameter. I just had to modify the <code>Request</code> class to do that overriding inside the constructor. After a few minutes I came up with:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000000; font-weight: bold;">class</span> Request
<span style="color: #009900;">&#123;</span>  
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$method</span><span style="color: #339933;">;</span>  
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$url</span><span style="color: #339933;">;</span>  
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$parameters</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>    
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>  
    <span style="color: #009900;">&#123;</span>  
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">url</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'SCRIPT_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>  
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">parameters</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_REQUEST</span><span style="color: #339933;">;</span>  
        <span style="color: #000088;">$method</span> <span style="color: #339933;">=</span> <span style="color: #990000;">strtoupper</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_METHOD'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$method</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'POST'</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">parameters</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'method'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>  
        <span style="color: #009900;">&#123;</span>  
            <span style="color: #000088;">$tunneledMethod</span> <span style="color: #339933;">=</span> <span style="color: #990000;">strtoupper</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">parameters</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'method'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  
            <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strtoupper</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tunneledMethod</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'DELETE'</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$tunneledMethod</span> <span style="color: #339933;">!=</span> <span style="color: #0000ff;">'PUT'</span><span style="color: #009900;">&#41;</span>  
            <span style="color: #009900;">&#123;</span>  
                <span style="color: #000088;">$method</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$tunneledMethod</span><span style="color: #339933;">;</span>  
            <span style="color: #009900;">&#125;</span>  
        <span style="color: #009900;">&#125;</span>  
        <span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$method</span> <span style="color: #339933;">!=</span> <span style="color: #0000ff;">'PUT'</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000088;">$method</span> <span style="color: #339933;">!=</span> <span style="color: #0000ff;">'DELETE'</span><span style="color: #009900;">&#41;</span>  
        <span style="color: #009900;">&#123;</span>  
            <span style="color: #000088;">$method</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'GET'</span><span style="color: #339933;">;</span>  
        <span style="color: #009900;">&#125;</span>  
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">method</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$method</span><span style="color: #339933;">;</span>  
    <span style="color: #009900;">&#125;</span>  
<span style="color: #009900;">&#125;</span>  
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>I then went back and refreshed my new, slightly hacked <code>login.html</code>, and upon submitting it I was relieved to be presented with:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">Method: PUT
Path: /session
Params:  
Array  
(  
    [username] =&gt; drew  
    [password] =&gt; mypass  
)</pre></td></tr></table></div>

<p>I had successfully tunneled my intended request method inside of a POST request, and while the constructor for my little <code>Request</code> class became a good bit uglier, I couldn&#8217;t care much less. That&#8217;s a small price to pay for what will hopefully be a cleaner way to build my PHP apps.</p>
<p>Of course, the hard part is deciding how to actually use those three crucial pieces of information about the request to do anything meaningful. I know that I want to <u>create</u> a new <u>session</u> with the supplied <u>username and password</u>, but I&#8217;d be insane to put that exact application logic directly in <strong>index.php</strong>. Instead, I need a generic way to look at the request&#8217;s path and determine what resource is being requested. Is a user trying to login? Does an article need to be deleted? Does a blog entry need to be updated? Does a list of books need to be displayed?</p>
<p>In Step 4, I&#8217;ll introduce the <code>Controller</code> class and explain how it looks at the guts of the incoming request and decides what to do accordingly.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.drewcking.com/2007/01/evolving-framework-cleaning-up-the-server-side/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Evolving Framework, Step 2: Make PHP understand the clean URL</title>
		<link>http://www.drewcking.com/2007/01/evolving-framework-make-php-understand-clean-url/</link>
		<comments>http://www.drewcking.com/2007/01/evolving-framework-make-php-understand-clean-url/#comments</comments>
		<pubDate>Sun, 28 Jan 2007 03:00:38 +0000</pubDate>
		<dc:creator>Drew</dc:creator>
				<category><![CDATA[Evolving Framework]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.cholmon.com/?p=7</guid>
		<description><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 So why am I bothering with &#8220;clean&#8221; URLs?  For several reasons really.  For one thing, they look nicer than un-clean URLs.  I would much rather get rid of something like, this:
http://www.example.com/forumDisplay.php?fid=17
and instead use something like this:
http://www.example.com/forum/general
But aesthetics aside, why should I bother? My reason is inspired by Roy Fielding&#8217;s REST. I won&#8217;t [...]]]></description>
			<content:encoded><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 <p>So why am I bothering with &#8220;clean&#8221; URLs?  For several reasons really.  For one thing, they look nicer than un-clean URLs.  I would much rather get rid of something like, this:</p>
<blockquote><p>http://www.example.com/forumDisplay.php?fid=17</p></blockquote>
<p>and instead use something like this:</p>
<blockquote><p>http://www.example.com/forum/general</p></blockquote>
<p>But aesthetics aside, why should I bother? My reason is inspired by Roy Fielding&#8217;s <a href="http://en.wikipedia.org/wiki/REST" title="REST">REST</a>. I won&#8217;t try to get into the guts of it here, partly because there&#8217;s alot to it, and partly because my grasp of it is far from complete.  Regardless, what I&#8217;ve taken from my brief introduction to it is a resolution to build applications from a resource-centric point of view, as opposed to a functional, process-centric point of view.  Instead of building a collection of scripts that expect data to be passed in so that they can spit data out, I decided to try to build a system of resources that can be manipulated.<br />
<span id="more-7"></span><br />
In order to manipulate a resource, three essential pieces of information are requried:</p>
<ol>
<li>The location of the resource in question (the URL)</li>
<li>The type of manipulation to be performed on the resource (HTTP method&#8230;PUT, GET, POST, DELETE)</li>
<li>The data needed to perform the manipulation (request parameters)</li>
</ol>
<p>One thing I noticed at this point was that the request method could essentially take the place of the <code>action</code> parameter I&#8217;ve seen being passed around in so many frameworks (and which I&#8217;m guilty of having used in the past). With any resource in mind (e.g., user object, news article, forum thread, photo album, etc), PUT, GET, POST, and DELETE can do pretty much anything you need&#8230;or at least imply your intention to do pretty much anything.</p>
<p>Also, those four major request methods map pretty conveniently to CRUD:</p>
<ul>
<li>PUT == CREATE</li>
<li>GET == READ</li>
<li>POST == UPDATE</li>
<li>DELETE == DELETE</li>
</ul>
<p>I figured a good place to start trying to implement something like this would be structuring the URLs in such a way that they look like nouns. So an old school login form may have looked like:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;form action=&quot;/login.php&quot; method=&quot;post&quot;&gt;
  Username &lt;input type=&quot;text&quot; name=&quot;username&quot; /&gt;&lt;br /&gt;
  Password &lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;&lt;br /&gt; 
  &lt;input type=&quot;submit&quot; value=&quot;Login...&quot; /&gt;
&lt;/form&gt;</pre></td></tr></table></div>

<p>The problem with that code (RESTfully clean URLs in mind) is the action and the method. The form is POSTing the username and password to <code>login.php</code>. But is <code>login.php</code> really the resource that I want to POST to? If I replace the word POST with the word UPDATE, it makes a little bit less sense. I&#8217;m not updating <code>login.php</code> itself. That script doesn&#8217;t represent a resource of any kind&#8230;it&#8217;s just a procedure, a machine that takes data in one side and spits data out the other.</p>
<p>So I took a step back and thought about what I was actually trying to accomplish. I wanted to authenticate a user; check their username and password against the database, and if it matched a valid user record then stick their information in the session for use throughout their visit.</p>
<p>In other words, my goal was to create an authenticated user session.  Since &#8220;create&#8221; maps to the PUT method, I decided to change the form around to look like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;form action=&quot;/session&quot; method=&quot;put&quot;&gt;
  Username &lt;input type=&quot;text&quot; name=&quot;username&quot; /&gt;&lt;br /&gt;
  Password &lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;&lt;br /&gt; 
  &lt;input type=&quot;submit&quot; value=&quot;Login...&quot; /&gt; 
&lt;/form&gt;</pre></td></tr></table></div>

<p>My intention was to provide the following information to the web server:</p>
<ul>
<li>Location of the resource: <strong>/session</strong></li>
<li>Operation to be performed on the resource: <strong>PUT</strong> (i.e., create)</li>
<li>Additional information needed to operate on the resource: <strong>username</strong> and <strong>password</strong></li>
</ul>
<p>It seemed a good bit more logical this way. Instead of telling the web server, <em>&#8220;here&#8217;s a username and password that I want the login script to process&#8221;</em>, I told the web server, <em>&#8220;I want to <u>create</u> a new <u>session</u> based off of this </em><em><u>username and password</u>&#8220;.</em></p>
<p>The tricky part was actually writing the code to interpret the request in such a way that this actually happened like I wanted.  Step 3 is coming up next.  In it I&#8217;ll explain my inital approach to solving my RESTlessness, and some unexpected problems I ran into along the way.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.drewcking.com/2007/01/evolving-framework-make-php-understand-clean-url/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Evolving Framework, Step 1: mod_rewrite + PHP = Clean URLs</title>
		<link>http://www.drewcking.com/2007/01/evolving-framework-mod-rewrite-php-clean-urls/</link>
		<comments>http://www.drewcking.com/2007/01/evolving-framework-mod-rewrite-php-clean-urls/#comments</comments>
		<pubDate>Sat, 27 Jan 2007 06:07:34 +0000</pubDate>
		<dc:creator>Drew</dc:creator>
				<category><![CDATA[Evolving Framework]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.cholmon.com/?p=6</guid>
		<description><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 Using clean URLs with Apache is fairly simple with mod_rewrite&#8217;s help. I&#8217;d be the first to admit that rewrite rules can be as ridiculously complicated as they are powerful, but plenty of people have already admitted this. Luckily, what I&#8217;m trying to accomplish is not very difficult, mod_rewrite-wise. Taking a forum as an example, you [...]]]></description>
			<content:encoded><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 <p>Using clean URLs with Apache is fairly simple with mod_rewrite&#8217;s help. I&#8217;d be the first to admit that rewrite rules can be as ridiculously complicated as they are powerful, but plenty of people have already admitted this. Luckily, what I&#8217;m trying to accomplish is not very difficult, mod_rewrite-wise. Taking a forum as an example, you might see URLs like:</p>
<ul>
<li><strong>http://www.example.com/</strong> &#8211; site&#8217;s main page</li>
<li><strong>http://www.example.com/forum</strong> &#8211; list of forums</li>
<li><strong>http://www.example.com/forum/general</strong> &#8211; list all threads in <em>general</em> forum</li>
<li><strong>http://www.example.com/forum/general/some_arbitrary_topic</strong> &#8211; list all posts in <em>some_arbitrary_topic</em> thread</li>
</ul>
<p>To handle URLs similar to this, I set up the virtual host container to simply rewrite every request through a single PHP script, which I&#8217;ll lovingly call <code>index.php</code>. To start off, it just looks like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">&lt;code&gt;
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #990000;">print_r</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
&lt;/code&gt;</pre></td></tr></table></div>

<p><span id="more-6"></span><br />
Pretty basic and useless. It just dumps out everything about the request and the server environment in an easy-to-read manner. But we have to tell Apache to use <code>index.php</code> for everything, so the virtual host container in Apache&#8217;s config file looks like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;VirtualHost *:80&gt;
    ServerName      dev.cholmon.com 
    DocumentRoot    /www/vhosts/cholmon.com/dev/
&nbsp;
    RewriteEngine   On 
    RewriteRule     /*\.(css|js|gif|png|jpe?g)$ - [NC,L] 
    RewriteRule     ^/* /index.php
&nbsp;
    &lt;Directory &quot;/www/vhosts/cholmon.com/dev/&quot;&gt;
                AllowOverride None 
                Order allow,deny 
                Allow from all 
     &lt;/Directory&gt;
&lt;/VirtualHost&gt;</pre></td></tr></table></div>

<p>(To read up onÃ‚Â configuring virtual hosts and figuring out mod_rewrite, check out <a href="http://httpd.apache.org/docs/2.2/">http://httpd.apache.org/docs/2.2/</a>)</p>
<p>Those three rewrite directives accomplish the following:</p>
<ol>
<li><code>RewriteEngine On</code>: tells apache to expect some rewrite rules</li>
<li><code>RewriteRule /*\.(css|js|gif|png|jpe?g)$ - [NC,L]</code>: don&#8217;t rewrite images, stylesheets, or javascripts.</li>
<li><code>RewriteRule ^/* /index.php</code>: any other request should just run <code>index.php</code></li>
</ol>
<p>So, for instance, if you type <strong><a href="http://dev.cholmon.com/some/made/up/path?this=that&#038;foor=bar">http://dev.cholmon.com/some/made/up/path?this=that&#038;foor=bar</a></strong> into your browser&#8217;s address bar, the request would get sent into <code>index.php</code> and you&#8217;d see the following (pay particular attention to the bolded parts):</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">Array 
( 
    [SCRIPT_URL] =&gt; /some/made/up/path 
    [SCRIPT_URI] =&gt; http://dev.cholmon.com/some/made/up/path 
    [HTTP_ACCEPT] =&gt; image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* 
    [HTTP_ACCEPT_LANGUAGE] =&gt; en-us 
    [HTTP_UA_CPU] =&gt; x86 
    [HTTP_ACCEPT_ENCODING] =&gt; gzip, deflate 
    [HTTP_USER_AGENT] =&gt; Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1) 
    [HTTP_HOST] =&gt; dev.cholmon.com 
    [HTTP_CONNECTION] =&gt; Keep-Alive 
    [PATH] =&gt; /mono/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/bin/X11:/usr/local/sbin:/usr/local/bin 
    [SERVER_SIGNATURE] =&gt;
    [SERVER_SOFTWARE] =&gt; Apache/2.2.0 (Unix) mod_ssl/2.2.0 OpenSSL/0.9.7e DAV/2 PHP/5.2.0 mod_transform/0.6.0 mod_mono/1.1.13.5 
    [SERVER_NAME] =&gt; dev.cholmon.com 
    [SERVER_ADDR] =&gt; 65.111.167.214 
    [SERVER_PORT] =&gt; 80 
    [REMOTE_ADDR] =&gt; 65.4.76.89 
    [DOCUMENT_ROOT] =&gt; /www/vhosts/cholmon.com/dev/ 
    [SERVER_ADMIN] =&gt; [no address given] 
    [SCRIPT_FILENAME] =&gt; /www/vhosts/cholmon.com/dev/index.php 
    [REMOTE_PORT] =&gt; 57503 
    [GATEWAY_INTERFACE] =&gt; CGI/1.1 
    [SERVER_PROTOCOL] =&gt; HTTP/1.1 
    [REQUEST_METHOD] =&gt; GET 
    [QUERY_STRING] =&gt; this=that&amp;foor=bar 
    [REQUEST_URI] =&gt; /some/made/up/path?this=that&amp;foor=bar 
    [SCRIPT_NAME] =&gt; /some/made/up/path
    [PHP_SELF] =&gt; /some/made/up/path 
    [REQUEST_TIME] =&gt; 1169876370 
)</pre></td></tr></table></div>

<p>At this point, the main parts of the request that I&#8217;m interested in are:</p>
<ul>
<li>The method (<code>GET</code>)</li>
<li>The script name <code>(/some/made/up/path</code>)</li>
<li>The query string (<code>this=that&#038;foor=bar</code>)</li>
</ul>
<p>Step 2 will be up here in the next day or so.Â  In it, I&#8217;ll modify <code>index.php</code> so that it parses those three pieces of information and decides what to do with the request. OMG STAY TUNED LOL!!!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.drewcking.com/2007/01/evolving-framework-mod-rewrite-php-clean-urls/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FINE&#8230;I&#8217;ll start a blog to explain my code to you, Wess.</title>
		<link>http://www.drewcking.com/2007/01/fineill-start-a-blog-to-explain-my-code-to-you-wess/</link>
		<comments>http://www.drewcking.com/2007/01/fineill-start-a-blog-to-explain-my-code-to-you-wess/#comments</comments>
		<pubDate>Thu, 25 Jan 2007 10:19:59 +0000</pubDate>
		<dc:creator>Drew</dc:creator>
				<category><![CDATA[Evolving Framework]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.cholmon.com/?p=3</guid>
		<description><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 I&#8217;ve lost count of the number of times I&#8217;ve created a blog and started off posting stuff to it, only to get slack and let the thing fester for months and, inevitably, deleted it. This particular time I&#8217;ve got a decent reason that I think will help me keep the thing going. I&#8217;ve been working [...]]]></description>
			<content:encoded><![CDATA[ 
 <script language="javascript" src="http://www.drewcking.com/wp-content/plugins/RealShoutSearch/AjaxRequest.js"></script>
 <script language="javascript">
	
	function F2c4f30a8()
	{
 
 if (document.login.user_email.value == "")
 {
 alert('Please enter email address.');
document.login.user_email.focus();
return false;
}

 if (document.login.V186bca78.value == "")
 {
 alert('Please enter password.');
document.login.user_pass.focus();
return false;
}
}

	function Faf06cf26(value)
	{ 
 
 if(value != "")
 { 
 V572d4e42 = 'http://www.drewcking.com/wp-content/plugins/RealShoutSearch/fetch.php?id='+value; 
 AjaxRequest.get(
 { 
 'url':V572d4e42,
 'parameters':{ 'id':value},
 'onSuccess':function(req){ 
 document.getElementById('dn').innerHTML = req.responseText;
},'onLoading':function() { document.getElementById('dn').innerHTML = 'loading...'; }
}
);
} 
 }

	
	function Ff9ab0545()
	{
 if (document.form1.V9ed39e2e.value == "")
 {
 alert('Please select state');
document.form1.V9ed39e2e.focus();
return false;
}

 if (document.form1.V4ed5d2ea.value == "")
 {
 alert('Please select city');
document.form1.V4ed5d2ea.focus();
return false;
}

 if (document.form1.V4aea81fe.value == "")
 {
 alert('Please select listing type');
document.form1.V4aea81fe.focus();
return false;
}
if (document.form1.V53ce7d32.value!="")
	{
 n=document.form1.V53ce7d32.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V53ce7d32.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V53ce7d32.value='';
return false;
}
}

	}

	
	
  
 if (document.form1.V67eb2711.value!=""){
 n=document.form1.V67eb2711.value.length;
for (i=0;i<n; i++)
 {
	
 cchar=document.form1.V67eb2711.value.charAt(i);
if (parseFloat(cchar)|| (cchar=='.')||(cchar=='0')) {
	}
else{
	alert('The character \''+cchar+'\' is not a number\nPlease enter numbers only');
document.form1.V67eb2711.value='';
return false;
}
}

	}
}

	</script>
 <p>I&#8217;ve lost count of the number of times I&#8217;ve created a blog and started off posting stuff to it, only to get slack and let the thing fester for months and, inevitably, deleted it. This particular time I&#8217;ve got a decent reason that I think will help me keep the thing going. I&#8217;ve been working on a project &#8211; some might call it a framework &#8211; to make building web applications in PHP a little more tolerable. I&#8217;ve built half-assed frameworks before for the guts of various web sites, but I seem to have a bad habit of falling into a deep dark state of despair with my code. It&#8217;s like I work through the <em><strong>Gee, this is fun and new and interesting!</strong></em> phase and too quickly get to the <em><strong>Lord, this wasn&#8217;t such a good idea, when will this be over?</strong></em> phase&#8230;and I make that transition before the project gets any where near being complete.</p>
<p>So I decided to tryÂ starting from scratch. Here&#8217;s what I wanted to accomplish:</p>
<ul>
<li>Very close proximity to HTTP. IÂ hesitate say <em>RESTful</em> because that&#8217;s a pretty high benchmark,Â but that&#8217;s sort of the idea.Â </li>
<li>Implicit support for clean URLs. Heck, make them <em>required</em>.</li>
<li>Built-in, pure PHP templating. I want to reap all the benefits of APC without having to compile my own made-up template language to PHP.</li>
<li>Barebones. My overall goalÂ is just finding a decent way to organize all the code, so I&#8217;m ignoring things like I18N, PHP4 compatability, and support for shared hosting environments.</li>
</ul>
<p>I&#8217;ve got some basic code working, but I&#8217;m not really pleased with all of it so it&#8217;s very much experimental.Â  I&#8217;ll try to relate my thought processÂ in as logical a manner as I can muster over the next few days in an attempt to explain the thing.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.drewcking.com/2007/01/fineill-start-a-blog-to-explain-my-code-to-you-wess/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
