<?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>Graphics by Greg &#187; PHP</title>
	<atom:link href="http://www.gregphoto.net/index.php/category/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.gregphoto.net</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Tue, 27 Dec 2011 00:24:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>InputValidator &#8211; Simple Input Validation for PHP</title>
		<link>http://www.gregphoto.net/index.php/2011/12/26/inputvalidator-simple-input-validation-for-php/</link>
		<comments>http://www.gregphoto.net/index.php/2011/12/26/inputvalidator-simple-input-validation-for-php/#comments</comments>
		<pubDate>Tue, 27 Dec 2011 00:24:00 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.gregphoto.net/?p=108</guid>
		<description><![CDATA[I recently needed a library for validating form input and everything seemed either verbose or required a huge number of files and libraries to be included. Here&#8217;s what I was looking for: Easy to include in projects without having to change include paths, mess with auto loaders, or include other frameworks Something that minimized the [...]]]></description>
			<content:encoded><![CDATA[<p>I recently needed a library for validating form input and everything seemed either verbose or required a huge number of files and libraries to be included.  Here&#8217;s what I was looking for:</p>
<ul>
<li>Easy to include in projects without having to change include paths, mess with auto loaders, or include other frameworks</li>
<li>Something that minimized the amount of validation code that needed to be written, preferably with a fluent interface</li>
<li>Ability to generate error messages that can be shown to the end user</li>
<li>Ability to transform data to data types needed by the rest of the script</li>
<li>Capability to validate against arbitrary regexes</li>
<li>Capability to validate against closures or other external functions</li>
</ul>
<p>I couldn&#8217;t find exactly what I was looking for, so I decided to write it myself.  I added the result, InputValidator, to my <a href="https://github.com/gneustaetter/gUtils">gUtils</a> collection of PHP classes on Github.  InputValidator is a standalone script for validating user input from forms or other sources.  </p>
<p>Everything is in a single file, making it easy to include in any (PHP 5.3+) project. Here&#8217;s some example usage:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?</span>
<span style="color: #b1b100;">require</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'gUtils/InputValidator.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// this could be from $_POST</span>
<span style="color: #000088;">$data</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
  <span style="color: #0000ff;">'name'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Greg Neustaetter'</span><span style="color: #339933;">,</span>
  <span style="color: #0000ff;">'email'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'greg@emailaddress.com'</span><span style="color: #339933;">,</span>
  <span style="color: #0000ff;">'website'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'http://www.gregphoto.net'</span><span style="color: #339933;">,</span>
  <span style="color: #0000ff;">'favoriteNumber'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'xyz'</span><span style="color: #339933;">,</span>
  <span style="color: #0000ff;">'date'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'11/11/2011'</span>
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// pass in the data to be validated</span>
<span style="color: #000088;">$v</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> gUtils\InputValidator<span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// validate each field</span>
<span style="color: #000088;">$v</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">field</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">required</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">length</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">50</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$v</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">field</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'email'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Email Address'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">required</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">email</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$v</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">field</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'website'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">url</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$v</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">field</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'favoriteNumber'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Your favorite number'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">intRange</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">100</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">toInt</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$v</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">field</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'date'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">toDateTime</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'m/d/Y'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">after</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// after the current time</span>
&nbsp;
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$v</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">allValid</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;pre&gt;'</span><span style="color: #339933;">;</span>
    <span style="color: #990000;">print_r</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$v</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getErrors</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// returns an array of errors indexed by field</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;pre&gt;'</span><span style="color: #339933;">;</span>
    <span style="color: #990000;">exit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> 
<span style="color: #000088;">$data</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$v</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getValues</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  <span style="color: #666666; font-style: italic;">// returns an array of values indexed by field</span>
<span style="color: #000088;">$name</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$v</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// get the value of name</span>
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$v</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">escape</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// escape the value of name for output with htmlspecialchars</span></pre></div></div>

<p>This script would print the following error array:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #990000;">Array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">'favoriteNumber'</span> <span style="color: #339933;">=&gt;</span> Your favorite number must be an integer between <span style="color: #cc66cc;">0</span> and <span style="color: #cc66cc;">100</span>
    <span style="color: #0000ff;">'date'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">Date</span> cannot be before <span style="color: #cc66cc;">12</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">24</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">2011</span>
<span style="color: #009900;">&#41;</span></pre></div></div>

<p>In addition to validation the library includes a few filters to manipulate data and cast it to formats needed by your code.  Take a look at <a href="https://github.com/gneustaetter/gUtils/wiki/InputValidator-Documentation">the documentation</a> on the Github wiki for a list of the 20 validators and the 8 filters. </p>
<p>Let me know if you find it useful or if you have any feedback&#8230; </p>
]]></content:encoded>
			<wfw:commentRss>http://www.gregphoto.net/index.php/2011/12/26/inputvalidator-simple-input-validation-for-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>RecursiveFileExtensionFilteredIterator</title>
		<link>http://www.gregphoto.net/index.php/2011/06/09/recursivefileextensionfilterediterator/</link>
		<comments>http://www.gregphoto.net/index.php/2011/06/09/recursivefileextensionfilterediterator/#comments</comments>
		<pubDate>Fri, 10 Jun 2011 05:28:36 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.gregphoto.net/?p=102</guid>
		<description><![CDATA[RecursiveFileExtensionFilteredIterator &#8211; rolls right off the tongue, right? Recently I had the need to find all of the files in a fairly big directory structure that were web pages &#8211; in my case, files with the .php and .html extensions. There were hundreds of directories and thousands of files to go through, so I decided [...]]]></description>
			<content:encoded><![CDATA[<p>RecursiveFileExtensionFilteredIterator &#8211; rolls right off the tongue, right?  </p>
<p>Recently I had the need to find all of the files in a fairly big directory structure that were web pages &#8211; in my case, files with the .php and .html extensions.  There were hundreds of directories and thousands of files to go through, so I decided to write a php script to find the files and then execute some code on the resulting files.  </p>
<p>I abstracted out the code to find files matching a particular extension and have posted the (minimal) code on <a href="https://github.com/gneustaetter/gutils">Github</a> as <a href="https://github.com/gneustaetter/gutils/blob/master/src/RecursiveFileExtensionFilteredIterator.php">RecursiveFileExtensionFilteredIterator</a>.  The 20 or so lines of code makes use of a couple of PHP&#8217;s <a href="http://www.php.net/manual/en/spl.iterators.php">SPL iterators</a> including the <a href="http://www.php.net/manual/en/class.recursivedirectoryiterator.php">Recursive Directory Iterator</a>, the <a href="http://www.php.net/manual/en/class.recursiveiteratoriterator.php">the Recursive Iterator Iterator</a>, and the <a href="http://www.php.net/manual/en/class.filteriterator.php">Filter Iterator</a>.  The result of this is a simple class that allows you to loop through a directory recursively to find only files that match a particular set of extensions, returning a <a href="http://us2.php.net/manual/en/class.splfileinfo.php">SplFileInfo</a> object for each file.  Here&#8217;s a simple example that prints out all of the paths:</p>

<div class="wp_syntax"><div 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: #009900;">&#40;</span><span style="color: #0000ff;">'RecursiveFileExtensionFilteredIterator.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$path</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'/path/to/starting/directory'</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$extensions</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'php'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'html'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$files</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> RecursiveFileExtensionFilteredIterator<span style="color: #009900;">&#40;</span><span style="color: #000088;">$path</span><span style="color: #339933;">,</span> <span style="color: #000088;">$extensions</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$files</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$file</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$file</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getPathname</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>that&#8217;s it &#8211; short and sweet.  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.gregphoto.net/index.php/2011/06/09/recursivefileextensionfilterediterator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PasswordHelper: PHP library for password hashing and more</title>
		<link>http://www.gregphoto.net/index.php/2011/01/19/passwordhelper-php-library-for-password-hashing-and-more/</link>
		<comments>http://www.gregphoto.net/index.php/2011/01/19/passwordhelper-php-library-for-password-hashing-and-more/#comments</comments>
		<pubDate>Thu, 20 Jan 2011 03:24:41 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.gregphoto.net/?p=92</guid>
		<description><![CDATA[Only two years since my last post I was fixing up an old website I had built to improve the security and as part of that I wanted to improve the way in which passwords were stored, created, and verified for complexity. As part of this I built PasswordHelper, a small PHP library (61 lines [...]]]></description>
			<content:encoded><![CDATA[<p>Only two years since my last post <img src='http://www.gregphoto.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>I was fixing up an old website I had built to improve the security and as part of that I wanted to improve the way in which passwords were stored, created, and verified for complexity.  As part of this I built <a href="/projects/passwordHelper">PasswordHelper</a>, a small PHP library (61 lines of code) described on the <a href="/projects/passwordHelper">overview/download/documentation/example</a> page as follows:</p>
<p>&#8212;&#8212;&#8212;&#8211;</p>
<p>PasswordHelper is a lightweight <b>BSD licensed</b> PHP class that has a number of password related utility functions that make it easy to:</p>
<ul>
<li><b>Securely store passwords</b> by hashing them with the adaptive <b>Blowfish/bcrypt</b> algorithm with random salt values</li>
<li>Compare user submitted passwords with stored password hashes</li>
<li>Generate <b>random passwords</b></li>
<li>Validate <b>password complexity</b> for length and matches to a configurable set of regular expressions</li>
</ul>
<p>	The library does nothing too complex &#8211; it just makes it easy to do common things to help create more secure PHP applications utilizing existing PHP functions through a simpler API.  Most of the <a href="http://www.php.net/manual/en/function.crypt.php">existing APIs</a> seem a bit&#8230;cryptic (ha ha, right?) and there are so many options and algorithms from which to choose.  Choosing the &#8216;wrong&#8217; algorithm for password hashing can lead to big problems, like the ability for hackers to <a href="http://www.duosecurity.com/blog/entry/brief_analysis_of_the_gawker_password_dump">brute force hundreds of thousands of passwords from your database in an hour</a>.</p>
<p>&#8212;&#8212;&#8212;&#8211; </p>
<p>Here&#8217;s a quick example of how it is used:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">require</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'PasswordHelper.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$pass</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> PasswordHelper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Hash a password with bcrypt and a random salt before storing it in a database</span>
<span style="color: #000088;">$hash</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$pass</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">generateHash</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'myP@ssword'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Validate the password against the stored hash on a login attempt</span>
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$pass</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">compareToHash</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'myWrongPassword'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$hash</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// password matches	</span>
<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// password doesn't match</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Generate a random password</span>
<span style="color: #000088;">$randomPassword</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$pass</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">generateRandomPassword</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Validate the complexity of a password</span>
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$pass</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">checkPasswordComplexity</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$password</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// password meets requirements	</span>
<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// password doesn't meet requirements</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><a href="/projects/passwordHelper">Check it out</a> if you need some help with passwords in your PHP application&#8230; </p>
]]></content:encoded>
			<wfw:commentRss>http://www.gregphoto.net/index.php/2011/01/19/passwordhelper-php-library-for-password-hashing-and-more/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP5 Defensio Class</title>
		<link>http://www.gregphoto.net/index.php/2007/11/24/php5-defensio-class/</link>
		<comments>http://www.gregphoto.net/index.php/2007/11/24/php5-defensio-class/#comments</comments>
		<pubDate>Sat, 24 Nov 2007 23:46:32 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.gregphoto.net/index.php/2007/11/24/php5-defensio-class/</guid>
		<description><![CDATA[Looooong time since I&#8217;ve written anything here &#8211; about 9 months! This time around I&#8217;ve put together a simple PHP5 class for communicating with the Defensio web service. Defensio has an example PHP class, but unfortunately it is PHP4 only and it&#8217;s more fun to rewrite it, right? For those who don&#8217;t know about Defensio, [...]]]></description>
			<content:encoded><![CDATA[<p>Looooong time since I&#8217;ve written anything here &#8211; about 9 months!  This time around I&#8217;ve put together a simple PHP5 class for communicating with the <a href="http://www.defensio.com">Defensio</a> web service.  Defensio has an example PHP class, but unfortunately it is PHP4 only and it&#8217;s more fun to rewrite it, right?</p>
<p>For those who don&#8217;t know about Defensio, it is a web service for determining whether a comment on a blog or message in an application is spam.  To use it, you must first <a href="http://defensio.com/signup">register</a> for an API key.  Defensio is very similar to the venerable Akismet (see <a href="http://www.gregphoto.net/index.php/2006/06/11/akismet-and-the-zend-framework/">the article I wrote on Akismet</a>) but they provide a couple other features such an indication of the &#8216;spaminess&#8217; of an individual message.  Akismet has worked out great for me (123,419 spam comments caught so far!), but I figured it would be good to try out something new as well.</p>
<p>The class is a PHP5 class and the public methods are reasonably well commented.  The bottom of this post has a link to a test application and a download of the class/test application.  So&#8230;the usage of this class is quite straightforward, as shown below:</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
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">require</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'library/Gregphoto/Defensio.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">require</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'library/Gregphoto/Defensio/Adapter/Streams.php);
&nbsp;
$apiKey = '</span>mysecretapikey<span style="color: #0000ff;">';
$siteUrl = '</span>http<span style="color: #339933;">:</span><span style="color: #666666; font-style: italic;">//my.secret.site.url.com';</span>
&nbsp;
<span style="color: #000088;">$defensio</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Gregphoto_Defensio<span style="color: #009900;">&#40;</span><span style="color: #000088;">$apiKey</span><span style="color: #339933;">,</span><span style="color: #000088;">$siteUrl</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$defensio</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setHttpClient</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Gregphoto_Defensio_Adapter_Streams<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$params</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
	<span style="color: #0000ff;">'user-ip'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REMOTE_ADDR'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span>
	<span style="color: #0000ff;">'article-date'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'2007/11/24'</span><span style="color: #339933;">,</span>
	<span style="color: #0000ff;">'comment-author'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Big Bad Spammer'</span><span style="color: #339933;">,</span>
	<span style="color: #0000ff;">'comment-type'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'comment'</span><span style="color: #339933;">,</span>
	<span style="color: #0000ff;">'comment-content'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'please click links and buy viagra'</span><span style="color: #339933;">,</span>
	<span style="color: #0000ff;">'comment-author-email'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'bigbadspammer@annoying.com'</span><span style="color: #339933;">,</span>
	<span style="color: #0000ff;">'comment-author-url'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'http://www.annoying.com'</span>
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$defensio</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">audit_comment</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$params</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: #000088;">$result</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'spam'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'true'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;Comment is spam with a spam score of &quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$result</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'spaminess'</span><span style="color: #009900;">&#93;</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: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;Comment is not spam&quot;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>A couple key points on usage:</p>
<ul>
<li>Each Gregphoto_Defensio object requires an Http adapter that it will use to make Http POST requests to the Defensio web service.  I originally hardcoded it to use the Zend_Http_Client from the Zend Framework, but figured this could discourage people from using it.  Then I wrote up a quick adapter to use PHP&#8217;s Http Stream Wrappers, but realized that didn&#8217;t work on my Dreamhost account, so I added in an extra one for the Curl extension.  In theory I should have added a Gregphoto_Defensio_Adapter_Interface class, but I was lazy and didn&#8217;t want to add in an extra file.</li>
<li>Each Gregphoto_Defensio object can be used to make many requests</li>
<li>All of the current <a href="http://www.defensio.com/api">Defensio API&#8217;s</a> are covered by the class.  These are covered by the following methods in the Gregphoto_Defensio class:
<ul>
<li>validate_key</li>
<li>announce_article</li>
<li>audit_comment</li>
<li>report_false_negatives</li>
<li>report_false_positives</li>
<li>get_stats</li>
</ul>
</li>
<li>Each of these methods takes a single parameter, an associative array of options as defined by the Defensio API.  Each API also returns an associative array of response parameters.  Two static utility methods Gregphoto_Defensio::getActions (returns a list of defensio methods such as &#8216;validate-key&#8217;) and Gregphoto_Defensio::getActionDetails (returns a list of required parameters, optional parameters, and response parameters for a specific Defensio action) are provided in order to get the details of the input and output parameters.
</ul>
<p>I created a simple <a href="http://www.gregphoto.net/projects/defensio/test">test application</a> which can be used to test Gregphoto_Defensio and all of the APIs provided by Defensio.</p>
<p><a href="http://www.gregphoto.net/projects/defensio/Gregphoto_Defensio.zip">Download the Gregphoto_Defensio class and the test application</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gregphoto.net/index.php/2007/11/24/php5-defensio-class/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Announcing Gregphoto_Image &#8211; a PHP5/GD2 Thumbnail Class</title>
		<link>http://www.gregphoto.net/index.php/2007/02/03/announcing-gregphoto_image-a-php5gd2-thumbnail-class/</link>
		<comments>http://www.gregphoto.net/index.php/2007/02/03/announcing-gregphoto_image-a-php5gd2-thumbnail-class/#comments</comments>
		<pubDate>Sat, 03 Feb 2007 21:41:41 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.gregphoto.net/index.php/2007/02/03/announcing-gregphoto_image-a-php5gd2-thumbnail-class/</guid>
		<description><![CDATA[I put together a simple, lightweight PHP class for generating thumbnail images. The class is compatible with PHP5 and uses the GD2 extension (included by default with PHP5) to create JPEG, PNG, and GIF thumbnails. I&#8217;ve setup a Google Code project for it: Gregphoto_Image where you can checkout the source from SVN and file bugs. [...]]]></description>
			<content:encoded><![CDATA[<p>I put together a simple, lightweight PHP class for generating thumbnail images.  The class is compatible with PHP5 and uses the GD2 extension (included by default with PHP5) to create JPEG, PNG, and GIF thumbnails.  I&#8217;ve setup a <a href="http://code.google.com/hosting">Google Code</a> project for it: <a href="http://code.google.com/p/gregphotoimage/">Gregphoto_Image</a> where you can checkout the source from SVN and file bugs.</p>
<p>The class has the following basic features:</p>
<ul>
<li>Ability to read JPEG, PNG, or GIF images</li>
<li>Ability to output JPEG, PNG, or GIF images</li>
<li>4 modes of thumbnail creation
<ul>
<li><i>MAX_HEIGHT</i> &#8211; you specify a maximum height and the dimensions are calculated based off of the height</li>
<li><i>MAX_WIDTH</i> &#8211; you specify a maximum width and the dimensions are calculated based off of the width</li>
<li><i>BEST_FIT</i> &#8211; you specify a maximum height and width and the dimensions are calculated so that the thumbnail<br />
	    is as large as possible without exceeding the maximum height or width</li>
<li><i>EXACT</i> &#8211; you specify a maximum height and width and these are directly used.  Causes distortion if the<br />
	    chosen aspect ratio is different from the aspect ratio of the image</li>
</ul>
</li>
<li>Renders/saves images in their input format by default, but allows changing the format.  For example, input a GIF but output a PNG</li>
<li>Fully documented object oriented code</li>
<li>Fluent interface for creating thumbnails with a minimal amount of code</li>
</ul>
<p>The class is licensed under the MIT license, which basically means it can be used and modified by anyone &#8211; for personal or commercial use.</p>
<p>You can <a href="http://code.google.com/p/gregphotoimage/">Download it</a> from the project page on Google Code.  You can <a href="http://www.gregphoto.net/projects/gregphoto_image/samples">view examples</a> of it running on my site &#8211; the examples are checked into SVN and can be viewed on the project site.  You can also <a href="http://www.gregphoto.net/projects/gregphoto_image/docs">view the docs</a>.</p>
<p>Example usage:</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: #b1b100;">require</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'path/to/Gregphoto_Image.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Gregphoto_Image<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'path/to/sample/image.jpg'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setMaxHeight</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">200</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setMaxWidth</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">200</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setJpegQuality</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">90</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">resize</span><span style="color: #009900;">&#40;</span>Gregphoto_Image<span style="color: #339933;">::</span><span style="color: #004000;">BEST_FIT</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">showThumbnail</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$image</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Gregphoto_Image<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'../images/fan.jpg'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setMaxHeight</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">200</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setJpegQuality</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">90</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">resize</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">showThumbnail</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>


<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="php" style="font-family:monospace;"><span style="color: #b1b100;">require</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'path/to/Gregphoto_Image.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Gregphoto_Image<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'path/to/image.jpg'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setMaxHeight</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">200</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setMaxWidth</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">200</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setJpegQuality</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">90</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setOutputType</span><span style="color: #009900;">&#40;</span>IMAGETYPE_PNG<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">resize</span><span style="color: #009900;">&#40;</span>Gregphoto_Image<span style="color: #339933;">::</span><span style="color: #004000;">BEST_FIT</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">saveThumbnail</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'path/to/thumbnail.png'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gregphoto.net/index.php/2007/02/03/announcing-gregphoto_image-a-php5gd2-thumbnail-class/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Ajax Form Validation</title>
		<link>http://www.gregphoto.net/index.php/2006/07/30/ajax-form-validation/</link>
		<comments>http://www.gregphoto.net/index.php/2006/07/30/ajax-form-validation/#comments</comments>
		<pubDate>Mon, 31 Jul 2006 00:04:58 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.gregphoto.net/index.php/2006/07/30/ajax-form-validation/</guid>
		<description><![CDATA[Recently I put together a reusable Ajax form validation component that I&#8217;d like to share. It is a JavaScript object that collects the values of all of the elements in a form, sends it for processing to the server, and displays any errors. If there are no errors it submits the form. There are several [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I put together a reusable Ajax form validation component that I&#8217;d like to share.  It is a JavaScript object that collects the values of all of the elements in a form, sends it for processing to the server, and displays any errors.  If there are no errors it submits the form.  There are several benefits to this approach</p>
<ul>
<li>Allows you to perform complex validation, such as verifying the uniqueness of a username, or checking something in the database&#8230;all without reloading the page</li>
<li>Allows you to use the same validation routine for both client-side validation and server-side validation</li>
<li>Reduces the amount of client-side code needed for validation</li>
</ul>
<p>The JavaScript used in <a href="http://www.gregphoto.net/projects/ajaxValidate">my example</a> requires the <a href="http://prototype.conio.net/">Prototype library</a>.  My example uses PHP to perform the validation &#8211; more specifically, I&#8217;ve used several components of the <a href="http://framework.zend.com">Zend Framework</a> (PHP5 only).  The example uses:</p>
<ul>
<li>Zend_Controller_* classes including the new RewriteRouter to handle the routing within the application</li>
<li>Zend_View to handle the output</li>
<li>Zend_View_Helper_* classes to build form elements</li>
<li>Zend_Config to read in configuration options</li>
<li>Zend_Filter to perform several field validations</li>
<li>Zend_Json to serialize PHP variables/objects to <a href="http://www.json.org/">JSON objects</a></li>
</ul>
<p>Did I need all of this stuff on the server-side to put together a simple form validation example? Heck no, but when I&#8217;m experimenting with new stuff I like to use a lot of new components so I can learn more about them and be prepared for when I actually do need to use all of this fire power.  I&#8217;ve been following the Zend Framework carefully, so I wanted to use some of the stuff I hadn&#8217;t used yet &#8211; particularly the controller architecture.</p>
<h3>The HTML and JavaScript</h3>
<p>Ok, back to how this JavaScript is used.  It&#8217;s actually really quite simple.  First, you need to include the JavaScript files for both Prototype and <a href="http://www.gregphoto.net/projects/ajaxValidate/static/js/ajaxFormValidate.js">AjaxFormValidator</a> in the head of your HTML document:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;script src=&quot;/ajaxValidate/static/js/prototype.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;/ajaxValidate/static/js/ajaxFormValidate.js&quot;&gt;&lt;/script&gt;</pre></td></tr></table></div>

<p>Next, you add an &#8216;onSubmit&#8217; handler to the form you&#8217;d like to validate &#8211; in this case, mine looks like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;form action=&quot;/ajaxValidate/index/success&quot; method=&quot;POST&quot; onSubmit=&quot;return submitForm(this);&quot;&gt;</pre></td></tr></table></div>

<p>The form action is set to the page I&#8217;d like the script to go to if the validation is successful.  The onSubmit calls a custom function that we still need to define.  It passes &#8216;this&#8217; as an argument &#8211; the &#8216;this&#8217; refers to the form element itself.</p>
<p>Now we define the submitForm() function that the onSubmit of the form will call &#8211; it looks like the following:</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="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> submitForm<span style="color: #009900;">&#40;</span>form<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	validator <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> AjaxFormValidator<span style="color: #009900;">&#40;</span>form<span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;/ajaxValidate/index/validate&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	validator.<span style="color: #660066;">errorDisplay</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">'inline'</span><span style="color: #339933;">;</span>
	validator.<span style="color: #660066;">inlineElem</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">'errorDiv'</span><span style="color: #339933;">;</span>
	<span style="color: #000066; font-weight: bold;">return</span> validator.<span style="color: #660066;">validate</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>This function first creates a new AjaxFormValidator object, passing it the form element (or the form id) and the url the validation request should be sent to.  The next two lines setup the type of error display that should happen.  The following error display types are supported:</p>
<ul>
<li>alert: The default option.  Displays all errors in a JavaScript alert box.</li>
<li>inline: Displays errors within an element that is defined on the page.  You need to set the element name with validator.inlineElem.  In this example, errors will be shown in a div with id=&#8221;errorDiv&#8221;.</li>
<li>none: errors won&#8217;t be shown to the user.  The will be available as an array of errors in the errors property of the validator (i.e. validator.errors).  If there are no errors the property will be set to false.  Once you have the errors you can perform more advanced error handling/display to the user.</li>
</ul>
<p>Lastly, validator.validate() will send the values in the form, in an HTTP POST, to the validation url you&#8217;ve provided (/ajaxValidate/index/validate in this case).  If there are no errors the form will be submitted, if there are errors the will be shown (or not shown if you&#8217;ve chosen &#8216;none&#8217; as the errorDisplay).</p>
<h3>The PHP</h3>
<p>Once the request is sent it will eventually arrive at the server for processing &#8211; in this case, through the magic of routing, it is going to end up in my IndexController in the validateAction method.  This function is shown below:</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
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> validateAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000088;">$errors</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getErrors</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_POST</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;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$errors</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$errors</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">echo</span> Zend_Json<span style="color: #339933;">::</span><span style="color: #004000;">encode</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$errors</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #339933;">&lt;/</span>php<span style="color: #339933;">&gt;</span>
This <span style="color: #000000; font-weight: bold;">function</span> calls another method within the IndexController <span style="color: #000000; font-weight: bold;">class</span> called getErrors<span style="color: #339933;">,</span> passing in the entire <span style="color: #990000;">array</span> of POST arguments <span style="color: #009900;">&#40;</span>values in the form<span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span>  It receives back an <span style="color: #990000;">array</span> full of error strings<span style="color: #339933;">.</span>  <span style="color: #b1b100;">If</span> there are no errors<span style="color: #339933;">,</span> it changes the value of the <span style="color: #000088;">$error</span> variable to <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">.</span>  Lastly<span style="color: #339933;">,</span> it uses Zend_Json to convert the PHP <span style="color: #990000;">array</span><span style="color: #339933;">/</span>Boolean into the equivalent JavaScript <span style="color: #990000;">array</span><span style="color: #339933;">/</span>Boolean<span style="color: #339933;">.</span>  This string is printed and sent back to the client<span style="color: #339933;">.</span>
&nbsp;
The getErrors <span style="color: #000000; font-weight: bold;">function</span> itself is very straightforward <span style="color: #339933;">-</span> it just does a couple validations and returns back an <span style="color: #990000;">array</span> of the errors<span style="color: #339933;">.</span>
<span style="color: #339933;">&lt;</span>pre lang<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;php&quot;</span> line<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;1&quot;</span><span style="color: #339933;">&gt;</span>
<span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> getErrors<span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000088;">$errors</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: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>Zend_Filter<span style="color: #339933;">::</span><span style="color: #004000;">isRegex</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'fname'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'/^[a-z]+[a-z 0-9-_]*$/i'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000088;">$errors</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'First Name is required and may only contain letters, numbers, and spaces'</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>Zend_Filter<span style="color: #339933;">::</span><span style="color: #004000;">isRegex</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'lname'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'/^[a-z]+[a-z 0-9-_]*$/i'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000088;">$errors</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'Last Name is required and may only contain letters, numbers, and spaces'</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>Zend_Filter<span style="color: #339933;">::</span><span style="color: #004000;">isRegex</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'email'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'/^[_a-zA-Z-]+[._a-zA-Z0-9-]+@[a-zA-Z0-9-]+\.[.a-zA-Z0-9]+$/'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000088;">$errors</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'Email is required and must be a valid email address'</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>Zend_Filter<span style="color: #339933;">::</span><span style="color: #004000;">isAlnum</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> <span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">12</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000088;">$errors</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'Password must consist of only letters and numbers and must be between 6 and 12 characters'</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">return</span> <span style="color: #000088;">$errors</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p><a href="http://www.gregphoto.net/projects/ajaxValidate">Check it out, in action</a>.  And that&#8217;s about it &#8211; pretty simple, huh?</p>
<p>You can download:</p>
<ul>
<li><a href="http://www.gregphoto.net/projects/ajaxValidate/static/js/ajaxFormValidate.js">The JavaScript</a></li>
<li><a href="http://www.gregphoto.net/projects/ajaxValidate/ajaxFormValidate.zip">The whole PHP project</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.gregphoto.net/index.php/2006/07/30/ajax-form-validation/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>gCards Forum Up!</title>
		<link>http://www.gregphoto.net/index.php/2006/07/03/gcards-forum-up/</link>
		<comments>http://www.gregphoto.net/index.php/2006/07/03/gcards-forum-up/#comments</comments>
		<pubDate>Mon, 03 Jul 2006 23:41:02 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[gCards]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.gregphoto.net/index.php/2006/07/03/gcards-forum-up/</guid>
		<description><![CDATA[Many folks have complained since I took down the forum that was up for the support of gCards. Now, I&#8217;ve got a new forum up, this one powered by Vanilla. Hopefully it&#8217;ll do a bit better than the last one. Check it out]]></description>
			<content:encoded><![CDATA[<p>Many folks have complained since I took down the forum that was up for the support of gCards.  Now, I&#8217;ve got a new forum up, this one powered by <a href="http://getvanilla.com/">Vanilla</a>.  Hopefully it&#8217;ll do a bit better than the last one.</p>
<p><a href="http://www.gregphoto.net/gcards/vanilla">Check it out</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gregphoto.net/index.php/2006/07/03/gcards-forum-up/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Experimenting with Google Checkout and PHP</title>
		<link>http://www.gregphoto.net/index.php/2006/07/01/experimenting-with-google-checkout-and-php/</link>
		<comments>http://www.gregphoto.net/index.php/2006/07/01/experimenting-with-google-checkout-and-php/#comments</comments>
		<pubDate>Sat, 01 Jul 2006 20:14:02 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.gregphoto.net/index.php/2006/07/01/experimenting-with-google-checkout-and-php/</guid>
		<description><![CDATA[Having put together a couple websites (Redstone Studios and Althea) that integrate with Paypal for providing checkout capabilities, I was very interested to look at Google Checkout when it was released this past week. My experience with the Paypal integration was not so good &#8211; while I eventually got it to work, it took a [...]]]></description>
			<content:encoded><![CDATA[<p>Having put together a couple websites (<a href="http://www.redstonestudios.com">Redstone Studios</a> and <a href="http://www.althearocks.com">Althea</a>) that integrate with Paypal for providing checkout capabilities, I was very interested to look at <a href="http://checkout.google.com">Google Checkout</a> when it was released this past week.  My experience with the Paypal integration was not so good &#8211; while I eventually got it to work, it took a ton of experimentation, searching for documentation, and guessing why things weren&#8217;t working (i.e. no meaningful error messages).  Luckily, Google Checkout doesn&#8217;t seem to suffer from these problems &#8211; I had it up and running in no time and it seems very solid for what it does.  What does it do?  Well, it&#8217;s basically a checkout system where you can pass in a cart, users can pay by credit card, and then the money gets deposited in your bank account.  Google charges 2% of the transaction amount plus twenty cents.  The two percent covers the percent Google has to pay the credit card companies, and the twenty cents is some extra cash for Google.  If you use Google Adwords, you get a free credit on Google Checkout &#8211; for every 1 dollar spent on Adwords you get 10 dollars of sales with no costs.</p>
<p>Google provides sample PHP code for getting the integration going, but unfortunately the code is PHP4 only, and it is ugly ugly ugly code.  I decided to put together a simple class that allows simple integration with Google Checkout.  The class is PHP5 only because it uses PHP5&#8242;s DOM extension.</p>
<p>To use Google Checkout you need to create a Google Checkout account.  From there, you can get your merchant id and merchant key, both of which are needed to communicate with Google Checkout.  The Google Checkout API works by POSTING XML over HTTP.  While <a href="http://code.google.com/apis/checkout/developer/index.html#api_details">Google&#8217;s API</a> is very flexible, I&#8217;ve chosen to implement a subset that I think would be useful for many people.  Also, I&#8217;ve only implemented this class to support the creation of the cart and submission to Google, I haven&#8217;t included any functionality for greater integration.  This greater integration would involve creating web services that Google could call to update the website on changes to the order status, shipping, etc.  The way I&#8217;ve set this up, all of that is skipped, and store owner would receive orders via email or Google&#8217;s Checkout interface.</p>
<p>Limitations:</p>
<ul>
<li>No support for cart expiration</li>
<li>No support for merchant calculations for tax/shipping/gift certificates as these require HTTPS and I don&#8217;t have it and don&#8217;t care to use it</li>
<li>No support for requesting the buyers phone number because I didn&#8217;t notice that field until just now!</li>
<li>No support for shipping restrictions &#8211; i.e. shipping option 1 is only available in these zip codes/states/etc</li>
<li>No support for complicated tax rules.  Tax can be setup on a state by state basis.  One alternative tax rule &#8216;taxfree&#8217; is setup to allow certain items to be tax free.  No support for other alternative tax rules.</li>
<li>Currently doesn&#8217;t support customization of the form and checkout image</li>
</ul>
<p>In order to work around some of these limitations, I&#8217;ve provided a method called setDefaultXML which allows the developer to specify a default XML file to be used.  The class will then fill in the items, do the encryption, and generate the form and checkout image.  This allows much greater flexibility and support for all of Google&#8217;s options, when needed.</p>
<p>Here&#8217;s a simple example of how I might use it:</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
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">require</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'GoogleCheckout.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$merchant_id</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'XXXXXXXXXXXXXXX'</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$merchant_key</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'XXXXXXXXXXXXXXXXXXXXXX'</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$google</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Gregphoto_Service_Google_Checkout<span style="color: #009900;">&#40;</span><span style="color: #000088;">$merchant_id</span><span style="color: #339933;">,</span><span style="color: #000088;">$merchant_key</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setMode</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sandbox'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addItem</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Doolittle'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'Doolitle CD by The Pixies (1989)'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'11.98'</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addItem</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'PSCREEN18'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'18 inch Pizza Screen'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'7.99'</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addItem</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'MYWIDGET01'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'New tax free widget - Student Use Only'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'149.21'</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span><span style="color: #0000ff;">''</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'taxfree'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addItem</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'NDISC01'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'New Customer Discount'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'-10'</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">editCartUrl</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'http://www.gregphoto.net/index.php?action=editcart&amp;source=google'</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">continueShoppingUrl</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'http://www.gregphoto.net'</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setShipping</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'UPS Ground'</span><span style="color: #339933;">,</span><span style="color:#800080;">19.99</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setShipping</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'UPS Next Day'</span><span style="color: #339933;">,</span><span style="color:#800080;">27.99</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setShipping</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Instore Pickup'</span><span style="color: #339933;">,</span><span style="color:#800080;">4.99</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'pickup'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setStateTax</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'CA'</span><span style="color: #339933;">,</span><span style="color:#800080;">.0875</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setStateTax</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'IL'</span><span style="color: #339933;">,</span><span style="color:#800080;">.0525</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getHTMLForm</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$google</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">printXML</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>Now, for what&#8217;s going on:</p>
<ul>
<li>Line 1 includes the class</li>
<li>Lines 3 and 4 setup variables for the merchant id and merchant key</li>
<li>Line 6 instantiates the class, passing in the merchant id and key</li>
<li>Line 7 sets the class to use the Google Checkout Sandbox &#8211; this is a testing sandbox where you can setup fake accounts to use while creating your site.  Paypal offerers a much richer sandbox functionality.</li>
<li>Lines 8-11 add new line items to the cart, setting there name, description, price, quantity, notes, and special tax rules</li>
<li>Lines 12 and 13 setup the URLs the user should be sent to if the choose to edit the cart or continue shopping</li>
<li>Lines 14-16 setup various shipping options including their prices</li>
<li>Lines 17 and 18 setup taxes for the users in specific states.  Google Checkout supports much richer rules around taxation, but I kept it simple on a state-by-state level.</li>
<li>Line 20 outputs the HTML form and checkout image that will send the cart to Google Checkout and bring the user to the Google Checkout page</li>
<li>Line 21 shows the XML cart, for debugging purposes</li>
</ul>
<p><a href="http://www.gregphoto.net/projects/googlecheckout/">View this example running on my site</a><br />
<a href="http://www.gregphoto.net/projects/googlecheckout/docs">View the API of Gregphoto_Service_Google_Checkout</a><br />
<a href="http://www.gregphoto.net/projects/googlecheckout/googlecheckout.zip">Download the class and API docs</a><br />
<a href="http://code.google.com/apis/checkout/developer/index.html">View Google&#8217;s Develper Guide for Google Checkout</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gregphoto.net/index.php/2006/07/01/experimenting-with-google-checkout-and-php/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Akismet and the Zend Framework</title>
		<link>http://www.gregphoto.net/index.php/2006/06/11/akismet-and-the-zend-framework/</link>
		<comments>http://www.gregphoto.net/index.php/2006/06/11/akismet-and-the-zend-framework/#comments</comments>
		<pubDate>Mon, 12 Jun 2006 00:52:55 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.gregphoto.net/index.php/2006/06/11/akismet-and-the-zend-framework/</guid>
		<description><![CDATA[Inspired by Akismet is my Hero on blog.phpdeveloper.org and by the fact that Akismet has already stopped several thousand spam comments on my own WordPress blog, I decided to put together an Akismet class using the Zend Framework (resulting in this being PHP 5 only). For those of you who don&#8217;t know, Akismet is a [...]]]></description>
			<content:encoded><![CDATA[<p>Inspired by <a href="http://blog.phpdeveloper.org/?p=34">Akismet is my Hero</a> on blog.phpdeveloper.org and by the fact that Akismet has already stopped several thousand spam comments on my own WordPress blog, I decided to put together an Akismet class using the Zend Framework (resulting in this being PHP 5 only).  For those of you who don&#8217;t know, Akismet is a web service that you can send comments to and they&#8217;ll let you know whether or not they think it&#8217;s spam.  It does a great job of spotting spam and was a great addition to WordPress.</p>
<p>This class, which you can <a href="http://www.gregphoto.net/projects/akismet/akismet.zip">download along with api docs</a> uses the Zend Framework&#8217;s Zend_Http_Client functionality to perform HTTP posts to Akismet and get the responses back.  More specifically, it uses the version of Zend_Http_Client that&#8217;s currently in the incubator, not the one in the regular library.</p>
<p>Here&#8217;s a simple usage example:</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
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$api_key</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'your api key here'</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$website_front_page</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'http://www.gregphoto.net'</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$message</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
	<span style="color: #0000ff;">'comment_author'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'viagra-test-123'</span><span style="color: #339933;">,</span>
	<span style="color: #0000ff;">'comment_author_email'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'viagra-test-123@hotmails.com'</span><span style="color: #339933;">,</span>
	<span style="color: #0000ff;">'comment_author_url'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'http://www.viagra-test-123.com/ilovespam/'</span><span style="color: #339933;">,</span>
	<span style="color: #0000ff;">'comment_content'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">&quot;Please buy my spam.  Mechanically separated meat tastes great!&quot;</span>
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$akismet</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Gregphoto_Service_Akismet<span style="color: #009900;">&#40;</span><span style="color: #000088;">$api_key</span><span style="color: #339933;">,</span><span style="color: #000088;">$website_front_page</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: #000088;">$akismet</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">checkIsSpam</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$message</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'it is spam!'</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: #b1b100;">echo</span> <span style="color: #0000ff;">'it is not spam!!'</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>In addition to checking whether a message is spam (Gregphoto_Service_Akismet::checkIsSpam), the following methods are provided, covering the entirety of the <a href="http://akismet.com/development/api/">Akismet API</a>:</p>
<ul>
<li>Gregphoto_Service_Akismet::validateKey &#8211; checks whether or not your api key is valid</li>
<li>Gregphoto_Service_Akismet::submitSpam &#8211; submits a message to Akismet telling it that it is spam (normally a message that Akismet identified as not being spam)</li>
<li>Gregphoto_Service_Akismet::submitHam &#8211; tell Akismet that a message it identified as spam is not actually spam</li>
</ul>
<p>To get an API key for yourself, follow the instructions printed on blog.phpdeveloper.org:</p>
<blockquote><p>You’ll need to go signup over on WordPress.com and, once logged in, go to your “My Dashboard” (top left link), go to the “Users” tab at the top and right there at the top of the page you’ll see “Your WordPress.com API key is…”. Easy as pie.</p></blockquote>
<p>Signup for a free blog, but don&#8217;t worry&#8230;you only need to sign up in order to get a key &#8211; you don&#8217;t actually have to use the wordpress.com account for anything else&#8230;</p>
<p>For anyone looking to build a site or application using the Zend Framework that accepts comments &#8211; this could be a good little tool that should integrate very cleanly.</p>
<p>Enjoy, and let me know what you think.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gregphoto.net/index.php/2006/06/11/akismet-and-the-zend-framework/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Getting stock quotes with Yahoo and the Zend Framework</title>
		<link>http://www.gregphoto.net/index.php/2006/04/23/getting-stock-quotes-with-yahoo-and-the-zend-framework/</link>
		<comments>http://www.gregphoto.net/index.php/2006/04/23/getting-stock-quotes-with-yahoo-and-the-zend-framework/#comments</comments>
		<pubDate>Mon, 24 Apr 2006 06:08:51 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.gregphoto.net/index.php/2006/04/23/getting-stock-quotes-with-yahoo-and-the-zend-framework/</guid>
		<description><![CDATA[I&#8217;ve been experimenting with various pieces of the Zend Framework to get a better idea of how they work. I decided to put together a simple project using a few of them. What I wanted to do was create a class that allows the user to get stock quotes (and other stock information) from Yahoo! [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been experimenting with various pieces of the <a href="http://framework.zend.com">Zend Framework</a> to get a better idea of how they work.  I decided to put together a simple project using a few of them.  What I wanted to do was create a class that allows the user to get stock quotes (and other stock information) from Yahoo! Finance, modeled after the Zend_Service_* classes.  Yahoo provides stock information in a <a href="http://www.gummy-stuff.org/Yahoo-data.htm">CSV format</a>.  I used the following components of the Zend Framework:</p>
<ul>
<li><a href="http://framework.zend.com/manual/en/zend.httpclient.html">Zend_Http_Client</a> &#8211; provides a class for sending HTTP requests and getting the response.  I need this in order to fetch the CSV file from Yahoo!</li>
<li>Zend_Cache &#8211; currently in the &#8216;incubator&#8217;, this class allows me to cache the response so that the application doesn&#8217;t need to get data from Yahoo on every page request.</li>
<li><a href="http://framework.zend.com/manual/en/zend.json.html">Zend_Json</a> &#8211; allows for automatic serialization of objects, arrays, and strings into JSON format, perfect for using with AJAX applications.  This isn&#8217;t actually used in the library, but there&#8217;s an example of how it can be used with the result of the library.</li>
</ul>
<p>On my way through putting this together, I came across another couple of things I haven&#8217;t had much/any experience with:</p>
<ul>
<li><a href="http://us3.php.net/manual/en/function.stream-wrapper-register.php">Streams wrappers</a></li>
<li><a href="http://www.php.net/~helly/php/ext/spl/interfaceSeekableIterator.html">SPL SeekableIterator interface</a></li>
</ul>
<p><strong>The calling &#8216;application&#8217;</strong></p>
<p>My <a href="http://www.gregphoto.net/projects/stocks">test page</a> for this class is as follows:</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
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?</span>
<span style="color: #000000; font-weight: bold;">function</span> __autoLoad<span style="color: #009900;">&#40;</span><span style="color: #000088;">$className</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	Zend<span style="color: #339933;">::</span><span style="color: #004000;">loadClass</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$className</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #b1b100;">require</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Zend.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$stocks</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Gregphoto_Service_Yahoo_Stocks<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$stocks</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addStocks</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'GOOG'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'YHOO'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'MSFT'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'AMD'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'INTC'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$stocks</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setSymbols</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'s'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'n'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'l1'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'c1'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$stockResult</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$stocks</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStockInfo</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;">?&gt;</span>
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Yahoo Stocks with Zend Framework: Example&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
<span style="color: #000000; font-weight: bold;">&lt;?</span>
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$stockResult</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$stock</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;<span style="color: #006699; font-weight: bold;">{$stock-&gt;s}</span>: <span style="color: #006699; font-weight: bold;">{$stock-&gt;c1}</span>&lt;br&gt;&quot;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span>
&nbsp;
&lt;p&gt;And here is a JSON string representation of the results:&lt;/p&gt;
&nbsp;
<span style="color: #000000; font-weight: bold;">&lt;?=</span>Zend_Json<span style="color: #339933;">::</span><span style="color: #004000;">encode</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$stockResult</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getArray</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #000000; font-weight: bold;">?&gt;</span>
&lt;/body&gt;
&lt;/html&gt;</pre></td></tr></table></div>

<p>Key points:</p>
<ul>
<li>Lines 2-4 setup an autoLoad function to take care of loading the Zend Framework files whenever they&#8217;re requested</li>
<li>Line 7 instantiates the Gregphoto_Service_Yahoo_Stocks class</li>
<li>On line 8 we pass in an array of stocks we&#8217;d like information on</li>
<li>On line 9 we send in a list of symbols, indicating what information we would like on these stocks.  For a detailed list of all the information that is available, check out the following link: <a href="http://www.gummy-stuff.org/Yahoo-data.htm">http://www.gummy-stuff.org/Yahoo-data.htm</a></li>
<li>Line 10 sends the request and gets back a Gregphoto_Service_Yahoo_Stocks_ResultSet object back.  This class implements SeekableIterator, allowing simple iteration over the results.</li>
<li>Lines 18 &#8211; 20 loop through the results, printing two symbols out: s and c1.  These are the stock symbol and the change on last day of trading</li>
<li>Line 25 uses the Zend_Json class to encode the results in JSON format.  This would be perfect for sending back to a page in an Ajax environment</li>
</ul>
<p><strong>The stocks class</strong></p>
<p>I&#8217;ll focus here on a couple of the key methods of this class &#8211; most of them are fairly basic.  You can <a href="http://www.gregphoto.net/projects/stocks/stocks.zip">download all the files</a> to see the whole thing if you want.</p>
<p>The first function we&#8217;ll look at is the getStockInfo method.  Here&#8217;s what it looks like:</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
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getStockInfo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_object</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">cacheObj</span><span style="color: #009900;">&#41;</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;">getCacheObj</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #000088;">$cache</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">cacheObj</span><span style="color: #339933;">;</span>
	<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">generateYahooURL</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000088;">$id</span> <span style="color: #339933;">=</span> <span style="color: #990000;">md5</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</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: #339933;">!</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cache</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">test</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$id</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000088;">$stockArray</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStockArray</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000088;">$cache</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$stockArray</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: #000088;">$stockArray</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$cache</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">new</span> Gregphoto_Service_Yahoo_Stocks_ResultSet<span style="color: #009900;">&#40;</span><span style="color: #000088;">$stockArray</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>This performs the following steps:</p>
<ul>
<li>Gets a cache object if it doesn&#8217;t already exist</li>
<li>Calls a method to generate the URL for the stock request</li>
<li>Creates an md5 hash of the url to use as the cache identifier for the request</li>
<li>If too old, it calls the getStockArray method and saves its result to the cache, otherwise it loads this information from the cache</li>
<li>It returns a new Gregphoto_Service_Yahoo_Stocks_ResultSet object to the user</li>
</ul>
<p>This of course, left out the most critical part &#8211; getting the stock quote CSV data from Yahoo! and converting it into an associative array.  That takes place in the getStockArray method, shown below:</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
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">function</span> getStockArray<span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000088;">$http</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Zend_Http_Client<span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000088;">$response</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$http</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</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: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isSuccessful</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">require_once</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">dirname</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">__FILE__</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'/csvstream.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000088;">$stockArray</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: #000088;">$GLOBALS</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'Gregphoto_Yahoo_Stocks_Stream'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getBody</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000088;">$fp</span> <span style="color: #339933;">=</span> fope<span style="color: #339933;">.</span>n<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'csvstr://Gregphoto_Yahoo_Stocks_Stream'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'r+'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>		
		<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$row</span> <span style="color: #339933;">=</span> <span style="color: #990000;">fgetcsv</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$fp</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2000</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;,&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!==</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #000088;">$stockArray</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_combine</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">symbols</span><span style="color: #339933;">,</span><span style="color: #000088;">$row</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$GLOBALS</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'Gregphoto_Yahoo_Stocks_Stream'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">return</span> <span style="color: #000088;">$stockArray</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: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> Exception<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Unable to get data from Yahoo Finance&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Note: On line 8, I couldn&#8217;t get this damn thing to save unless I got rid of &#8216;fopen&#8217;, so I changed it to &#8216;fope.n&#8217;</p>
<p>My webhost, <a href="http://www.dreamhost.com">Dreamhost</a>, doesn&#8217;t support <a href="http://us3.php.net/manual/en/ref.filesystem.php#ini.allow-url-fopen">allow_url_fopen</a>, meaning I can&#8217;t use standard file functions such as file, fopen, or file_get_contents to get the CSV file from Yahoo.  Instead, here I use the Zend_Http_Client class to get stock quotes CSV from Yahoo!.  PHP has a built in function, <a href="http://us2.php.net/manual/en/function.fgetcsv.php">fgetcsv</a>, for converting CSVs to arrays&#8230;unfortunately it only works on file resources, like the ones you&#8217;d get if you opened the file with fopen&#8230;a function I can&#8217;t use to open a remote file.  I scratched my head for a while on this one.  One solution would be to save the contents of the response as a file on the filesystem and then use fgetcsv on the file.  I found an alternative after many a google search &#8211; <a href="http://us2.php.net/manual/en/function.stream-wrapper-register.php">stream_wrapper_register</a> &#8211; a function that lets you define a class that represents data as a stream&#8230;that can be used with all functions requiring a file resource.  Not only did I find the idea in the PHP manual, there was actually an example of using it for CSV data in the comments &#8211; now that&#8217;s service.  So here&#8217;s the steps:</p>
<ul>
<li>Instantiate a new Zend_Http_Client with the URL passed in from getStockInfo</li>
<li>Get the reponse object and if it was successful, continue, otherwise throw an exception</li>
<li>Require the csvstream.php class which has the csvstream class and the following line: stream_wrapper_register(&#8220;csvstr&#8221;, &#8220;csvstream&#8221;);  This registers the class for all urls beginning with csvstr://</li>
<li>Set a global variable with the value of the CSV file, the body of the HTTP response.  The csvstream class looks for the value to be converted to a stream in a global variable.</li>
<li>Use the fopen function to open csvstr://Gregphoto_Yahoo_Stocks_Stream, the second part of the URL being the name of the global variable I set</li>
<li>After this, we loop through the file and use the fgetcsv function to create an array, combine it with the symbols chosen to make a more user-friendly associative array.</li>
<li>Lastly, we unset the hack-ish global variable we had to set and return the array</li>
</ul>
<p>And that&#8217;s really the meat of it.  The rest of it is very straightforward.  The Gregphoto_Service_Yahoo_Stocks_ResultSet does nothing much more than implementing the SeekableIterator function and creating new Gregphoto_Service_Yahoo_Stocks_Result instances.  The Gregphoto_Service_Yahoo_Stocks_Result class itself is very simple, using the magical __get method to allow easier access to the array values, i.e. $stock->s instead of $stock['s'].  I could easily have skipped the resultset and result classes, but I decided to create them so that it would work in a similar fashion to the Zend_Service classes.  </p>
<p>All in all, I&#8217;ve found it to be very easy to work with the Zend Framework classes, though I&#8217;m still holding off on the controller/view classes until they firm up a bit and add native support for applications in subdirectories (supposedly in the next dot release).  </p>
<p>Hope you found this interesting&#8230;you can <a href="http://www.gregphoto.net/projects/stocks/stocks.zip">download the code here</a>, but don&#8217;t expect production worthy code, much documentation, or much support!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gregphoto.net/index.php/2006/04/23/getting-stock-quotes-with-yahoo-and-the-zend-framework/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

