<?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>Joey Rivera</title>
	<atom:link href="http://www.joeyrivera.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.joeyrivera.com</link>
	<description>Blogging about PHP, Zend Framework, and other interests.</description>
	<lastBuildDate>Sun, 19 May 2013 18:32:34 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.4.2</generator>
		<item>
		<title>Doctrine2 and Postgresql timestamp with millisecond issue</title>
		<link>http://www.joeyrivera.com/2013/doctrine2-and-postgresql-timestamp-with-millisecond-issue/</link>
		<comments>http://www.joeyrivera.com/2013/doctrine2-and-postgresql-timestamp-with-millisecond-issue/#comments</comments>
		<pubDate>Sun, 19 May 2013 18:30:58 +0000</pubDate>
		<dc:creator>Joey</dc:creator>
				<category><![CDATA[Doctrine2]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Postgres]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[doctrine2]]></category>
		<category><![CDATA[postgres]]></category>
		<category><![CDATA[postgresql]]></category>
		<category><![CDATA[psql]]></category>

		<guid isPermaLink="false">http://www.joeyrivera.com/?p=731</guid>
		<description><![CDATA[I&#8217;ve been doing a lot of work with Doctrine 2 and finding some issues when dealing with PostgreSQL and Doctrine which I&#8217;ll be blogging about. I&#8217;ve ignored this particular issue for some time and finally decided to address it. The issue is declaring a Doctrine entity property as datetime if the column in the db [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been doing a lot of work with Doctrine 2 and finding some issues when dealing with PostgreSQL and Doctrine which I&#8217;ll be blogging about. I&#8217;ve ignored this particular issue for some time and finally decided to address it.</p>
<p>The issue is declaring a Doctrine entity property as datetime if the column in the db is storing the timestamp with milliseconds such as &#8217;2012-01-01 10:12:35.542&#8242;. When you try to load that into your entity, Doctrine will give you an error. An example of how this can happen is declaring a column timestamp without time zone and using now() as the default value.</p>
<p>Here is an example of a Doctrine entity property declared as a datetime</p>
<div class="dean_ch" style="white-space: wrap;"><span class="coMULTI">/**<br />
* @Column(type=&quot;datetime&quot;)<br />
*/</span><br />
protected <span class="re0">$discontinued</span>;</div>
<p>And what the column sql declaration looks like</p>
<div class="dean_ch" style="white-space: wrap;">discontinued timestamp without time zone <span class="kw1">NOT</span> <span class="kw1">NULL</span>;</div>
<p>There are three solutions that work, one is to configure Doctrine to not use the default DateTime classes, or you can declare your datetime properties as strings in your entities and convert them to datetime yourself if needed and finally the other approach is to update your db to not store milliseconds. I considered all approaches are decided that it would be better and more efficient to update the db than to write some custom DateTime classes or treat dates as string. If you would like to tackle this issue by creating your own custom DateTime classes then follow this <a title="Doctrine2 Known vendor issues for DateTime" href="http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/known-vendor-issues.html">link</a> for more information.</p>
<p>I used the following query to identity all the timestamp columns in my db table:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">SELECT</span> table_name, column_name <span class="kw1">FROM</span> information_schema.<span class="kw1">COLUMNS</span> <span class="kw1">WHERE</span> table_catalog = <span class="st0">&#8216;gatweb2&#8242;</span> <span class="kw1">AND</span> table_schema = <span class="st0">&#8216;public&#8217;</span> <span class="kw1">AND</span> udt_name <span class="kw1">LIKE</span> <span class="st0">&#8216;timestamp%&#8217;</span> <span class="kw1">ORDER</span> <span class="kw1">BY</span> table_name <span class="kw1">ASC</span>;</div>
<p>Noticed I used like timestampe% instead of = timestamp. This is because you could have timestamptz (timestamp with time zone) columns as well. Once I had the list, I saved the results, did some search/replace magic to come up with alter statements for each table and ran the queries. I spent a little bit of time looking at cursors to see if I could write a cursor to loop through the list and alter each table but it was taking too long research and search/replaced was quick. This is what the alter queries look like for each table:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">ALTER</span> <span class="kw1">TABLE</span> <span class="st0">&quot;contact&quot;</span> <span class="kw1">ALTER</span> <span class="st0">&quot;date&quot;</span> <span class="kw1">SET</span> <span class="kw1">DATA</span> type timestamp<span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span> without time zone;</div>
<p>By altering my timestamp columns to timestamp(0), it lets Postgres know to remove milliseconds from all values as well as to not store milliseconds in the future.</p>
<p>An issue I ran into when running all my alter statements was that some views were referencing some of the columns I was about to alter and Postgres didn&#8217;t like that. I did some research and it seems my only choice was to drop those particular views, alter the tables, then recreate the views. I created a big script that did all that, ran it, and now all my issues are gone and my unit test passed.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeyrivera.com/2013/doctrine2-and-postgresql-timestamp-with-millisecond-issue/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Slides from Automation with Phing presentation for Codeworks 2012 Atlanta</title>
		<link>http://www.joeyrivera.com/2012/slides-from-automation-with-phing-presentation-for-codeworks-2012-atlanta/</link>
		<comments>http://www.joeyrivera.com/2012/slides-from-automation-with-phing-presentation-for-codeworks-2012-atlanta/#comments</comments>
		<pubDate>Sat, 13 Oct 2012 19:06:39 +0000</pubDate>
		<dc:creator>Joey</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[dbdeploy]]></category>
		<category><![CDATA[deploy]]></category>
		<category><![CDATA[phing]]></category>

		<guid isPermaLink="false">http://www.joeyrivera.com/?p=694</guid>
		<description><![CDATA[I had the pleasant opportunity to present at Codeworks this year. I&#8217;ve presented at the Atlanta PHP User Group a few times but this was my first time presenting at a conference. Overall I think it went well and I learned a lot from it. I picked Phing as a topic as we have been [...]]]></description>
			<content:encoded><![CDATA[<p>I had the pleasant opportunity to present at <a href="http://codeworks.phparch.com/">Codeworks</a> this year. I&#8217;ve presented at the <a href="http://atlantaphp.org/">Atlanta PHP User Group</a> a few times but this was my first time presenting at a conference. Overall I think it went well and I learned a lot from it. I picked Phing as a topic as we have been doing a lot with Phing in the last year at work. The presentation covers some of the improvements we&#8217;ve made to one of our applications by automating a few processes that we used to spend hours on. Here are the slides:</p>
<p>&nbsp;</p>
<object type='application/x-shockwave-flash' wmode='opaque' data='http://static.slideshare.net/swf/ssplayer2.swf?id=14561453&doc=automationwithphing-121002141156-phpapp02' width='514' height='421'><param name='movie' value='http://static.slideshare.net/swf/ssplayer2.swf?id=14561453&doc=automationwithphing-121002141156-phpapp02' /><param name='allowFullScreen' value='true' /></object>
<div><strong> <a title="Automation with phing" href="http://www.slideshare.net/joeyrivera/automation-with-phing-14561453" target="_blank">Automation with phing</a> </strong> from <strong><a href="http://www.slideshare.net/joeyrivera" target="_blank">Joey Rivera</a></strong></div>
<div></div>
]]></content:encoded>
			<wfw:commentRss>http://www.joeyrivera.com/2012/slides-from-automation-with-phing-presentation-for-codeworks-2012-atlanta/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automate SVN Export to Site w/ Bash Script</title>
		<link>http://www.joeyrivera.com/2011/automate-svn-export-to-site-w-bash-script/</link>
		<comments>http://www.joeyrivera.com/2011/automate-svn-export-to-site-w-bash-script/#comments</comments>
		<pubDate>Thu, 10 Nov 2011 16:30:19 +0000</pubDate>
		<dc:creator>Joey</dc:creator>
				<category><![CDATA[Other]]></category>
		<category><![CDATA[automate]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[export]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://www.joeyrivera.com/?p=685</guid>
		<description><![CDATA[So at work we are finalizing the setup of a new server environment. The site is in PHP and the code is all in SVN. We were trying to decide what process to use to export the SVN contents to the site and that&#8217;s where I decided to learn how to write a bash script. [...]]]></description>
			<content:encoded><![CDATA[<p>So at work we are finalizing the setup of a new server environment. The site is in PHP and the code is all in SVN. We were trying to decide what process to use to export the SVN contents to the site and that&#8217;s where I decided to learn how to write a bash script. This is my first and with some help from <a title="Jesse Charbneau" href="http://jess.thecharbneaus.com/">Jess</a> we created the following script. The script does the following:</p>
<ul>
<li>Does an info on the remote repo to get the revision number</li>
<li>Checks against local revision number which is stored in a file</li>
<li>If the revision numbers don&#8217;t match, it does a diff on both revisions and creates an list with the files that were changed</li>
<li>It then loops through each file and exports it to the site</li>
<li>Finally it stores the new revision number in the file</li>
</ul>
<div>Feel free to use this and tweak it for your needs. This is our first draft, at this point we&#8217;ll start cleaning it up and adding more functionality but it works. Make sure to add a cron job to run it every so often and enjoy.</div>
<div class="dean_ch" style="white-space: wrap;"><span class="re3">#!/bin/bash</span><br />
<span class="re3"># need to figure out what to <span class="kw1">do</span> on files that need to be deleted</span><br />
<span class="re2">TARGET_DIR=</span><span class="st0">&#8216;/path/to/site&#8217;</span><br />
<span class="re2">REPO=</span><span class="st0">&quot;svn://path.to.svn/repo&quot;</span><br />
<span class="re2">REVISION_FILE=</span><span class="st0">&#8216;.revision&#8217;</span></p>
<p><span class="kw3">echo</span> <span class="st0">&quot;Getting info from remote repo&quot;</span><br />
<span class="re2">REMOTE_VERSION=</span>$<span class="br0">&#40;</span>svn info <span class="re1">$REPO</span> | <span class="kw2">grep</span> Revision<span class="br0">&#41;</span><br />
<span class="re2">REMOTE_VERSION=</span>$<span class="br0">&#123;</span>REMOTE_VERSION: <span class="nu0">-4</span><span class="br0">&#125;</span> <span class="re3"># need to update to not hardcode <span class="nu0">4</span> spaces back</span><br />
<span class="re2">CURRENT_VERSION=</span>$<span class="br0">&#40;</span><span class="kw2">more</span> <span class="re1">$REVISION_FILE</span><span class="br0">&#41;</span></p>
<p><span class="kw3">echo</span> <span class="st0">&quot;Current Revision: $CURRENT_VERSION&quot;</span><br />
<span class="kw3">echo</span> <span class="st0">&quot;Remote Revision: $REMOTE_VERSION&quot;</span></p>
<p><span class="kw1">if</span> <span class="br0">&#91;</span> <span class="st0">&quot;$REMOTE_VERSION&quot;</span> -eq <span class="st0">&quot;$CURRENT_VERSION&quot;</span> <span class="br0">&#93;</span><br />
<span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;No export needed&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">exit</span> <span class="nu0">0</span><br />
<span class="kw1">fi</span></p>
<p><span class="kw3">echo</span> <span class="st0">&quot;Getting diffs between revisions&quot;</span><br />
<span class="re2">difflines=</span>`svn <span class="kw2">diff</span> &#8211;summarize -r <span class="re1">$CURRENT_VERSION</span>:<span class="re1">$REMOTE_VERSION</span> <span class="re1">$REPO</span> <span class="nu0">2</span>&gt;&amp;amp;<span class="nu0">1</span> | <span class="kw2">awk</span> <span class="st0">&#8216;{print $2}&#8217;</span>`</p>
<p><span class="re2">URL_LENGTH=</span>$<span class="br0">&#123;</span><span class="re3">#REPO<span class="br0">&#125;</span></span></p>
<p><span class="kw1">for</span> i <span class="kw1">in</span> `<span class="kw3">echo</span> <span class="re1">$difflines</span>`; <span class="kw1">do</span><br />
&nbsp; &nbsp;<span class="re2">FILENAME=</span>$<span class="br0">&#123;</span>i:<span class="re1">$URL_LENGTH</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw3">echo</span> <span class="st0">&quot;svn export ${i} ${TARGET_DIR}${FILENAME}&quot;</span><br />
&nbsp; &nbsp;svn <span class="kw3">export</span> <span class="re0">$<span class="br0">&#123;</span>i<span class="br0">&#125;</span></span> <span class="re0">$<span class="br0">&#123;</span>TARGET_DIR<span class="br0">&#125;</span></span><span class="re0">$<span class="br0">&#123;</span>FILENAME<span class="br0">&#125;</span></span><br />
<span class="kw1">done</span></p>
<p><span class="kw3">echo</span> <span class="st0">&quot;Saving revision number&quot;</span><br />
<span class="kw3">echo</span> <span class="re0">$<span class="br0">&#123;</span>REMOTE_VERSION<span class="br0">&#125;</span></span> &gt; <span class="re1">$REVISION_FILE</span></div>
]]></content:encoded>
			<wfw:commentRss>http://www.joeyrivera.com/2011/automate-svn-export-to-site-w-bash-script/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Zend_Json_Server and how to call it via JSON-RPC 2.0</title>
		<link>http://www.joeyrivera.com/2011/zend_json_server-and-how-to-call-it-via-json-rpc-2-0/</link>
		<comments>http://www.joeyrivera.com/2011/zend_json_server-and-how-to-call-it-via-json-rpc-2-0/#comments</comments>
		<pubDate>Wed, 05 Jan 2011 22:32:04 +0000</pubDate>
		<dc:creator>Joey</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[2.0]]></category>
		<category><![CDATA[json-rpc]]></category>
		<category><![CDATA[jsonrpc]]></category>
		<category><![CDATA[zend framework]]></category>
		<category><![CDATA[zend_json_server]]></category>

		<guid isPermaLink="false">http://www.joeyrivera.com/?p=656</guid>
		<description><![CDATA[So I started playing with Zend_Json_Server and was having a hard time trying to figure out how to call the server from a client. Finally I checked the JSON-RPC 2.0 spec and read a very important detail that I had not realized: The Request is expressed as a single JSON Object This was the key [...]]]></description>
			<content:encoded><![CDATA[<p>So I started playing with <a title="Zend_Json_Server docs" href="http://framework.zend.com/manual/en/zend.json.server.html">Zend_Json_Server</a> and was having a hard time trying to figure out how to call the server from a client. Finally I checked the <a title="Json-Rpc 2.0 specs" href="http://groups.google.com/group/json-rpc/web/json-rpc-1-2-proposal?pli=1#request-procedure-call">JSON-RPC 2.0 spec</a> and read a very important detail that I had not realized:</p>
<blockquote><p>The Request is expressed as a single JSON Object</p></blockquote>
<p>This was the key to my problem. There are 4 parameters that can be sent with each JSON-RPC 2.0 request but I was sending each as a post var which is not what Zend_Json_Server expects. It simply wants one json encoded object with all the parameters inside. The 4 available parameters are:</p>
<ol>
<li>jsonrpc &#8211; the version you are using; I&#8217;m using 2.0.</li>
<li>method &#8211; the name of the method you want to call in the server.</li>
<li>params &#8211; object of parameters your method needs. If you don&#8217;t need any, don&#8217;t send this param.</li>
<li>id &#8211; an identifier (anything you want) that will be sent to and from the server for this request.</li>
</ol>
<p>I&#8217;m using Zend_Http_Client() to make the request and here is an example:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="re0">$params</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;jsonrpc&#8217;</span> =&gt; <span class="st0">&#8217;2.0&#8242;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;method&#8217;</span> =&gt; <span class="st0">&#8216;find&#8217;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;params&#8217;</span> =&gt; <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st0">&#8217;326691&#8242;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;id&#8217;</span> =&gt; <span class="st0">&#8216;test&#8217;</span><br />
<span class="br0">&#41;</span>;</p>
<p><span class="re0">$http</span> = <span class="kw2">new</span> Zend_Http_Client<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$http</span>-&gt;<span class="me1">setUri</span><span class="br0">&#40;</span><span class="st0">&#8216;http://localhost/path/to/jsonrpc/server.php&#8217;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$http</span>-&gt;<span class="me1">setMethod</span><span class="br0">&#40;</span>Zend_Http_Client::<span class="me2">POST</span><span class="br0">&#41;</span>;<br />
<span class="re0">$http</span>-&gt;<span class="me1">setRawData</span><span class="br0">&#40;</span>json_encode<span class="br0">&#40;</span><span class="re0">$params</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p><a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="re0">$http</span>-&gt;<span class="me1">request</span><span class="br0">&#40;</span><span class="br0">&#41;</span>-&gt;<span class="me1">getBody</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
<p><span id="more-656"></span>And here is what I see in my browser when I make the call:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="br0">&#123;</span><br />
-result: <span class="br0">&#123;</span><br />
student_id: <span class="nu0">326691</span><br />
title: <span class="kw2">null</span><br />
first_name: <span class="st0">&quot;Accountbuilder&quot;</span><br />
last_name: <span class="st0">&quot;Random59&quot;</span><br />
middle_initial: <span class="st0">&quot;&quot;</span><br />
suffix: <span class="kw2">null</span><br />
address: <span class="st0">&quot;some place&quot;</span><br />
address2: <span class="kw2">null</span><br />
city: <span class="st0">&quot;Dallas&quot;</span><br />
-state: <span class="br0">&#123;</span><br />
state_id: <span class="nu0">11</span><br />
name: <span class="kw2">null</span><br />
abbr: <span class="kw2">null</span><br />
display_name: <span class="kw2">null</span><br />
sales_tax: <span class="nu0">0</span><br />
<span class="br0">&#125;</span><br />
zip: <span class="st0">&quot;30132&quot;</span><br />
phone: <span class="st0">&quot;111-111-1111&quot;</span><br />
fax: <span class="kw2">null</span><br />
username: <span class="kw2">null</span><br />
password: <span class="kw2">null</span><br />
<span class="br0">&#125;</span><br />
id: <span class="st0">&quot;test&quot;</span><br />
error: <span class="kw2">null</span><br />
jsonrpc: <span class="st0">&quot;2.0&quot;</span><br />
<span class="br0">&#125;</span></div>
<p>Basically, all I had to do was</p>
<ul>
<li>create an array of all the parameters I want to send on my request object. I&#8217;m calling the find method and passing an id</li>
<li>create a new client object</li>
<li>set the url to where your setting up your Zend_Json_Server</li>
<li>set the client to post (Zend_Json_Server only seems to handle post at this time)</li>
<li>json_encode your parameters array</li>
<li>pass the json_encoded object to the setRawData so it passes exactly what we want which is one json object to the server</li>
<li>call request to send the request and finally get body to show the response.</li>
</ul>
<p>Here is my code for the server.php file so you can see how I&#8217;m setting up the server:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="re0">$server</span> = <span class="kw2">new</span> Zend_Json_Server<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$server</span>-&gt;<span class="me1">setClass</span><span class="br0">&#40;</span><span class="st0">&#8216;Student&#8217;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$response</span> = <span class="re0">$server</span>-&gt;<span class="me1">handle</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="re0">$response</span>;</div>
<p>I setup the server instance, add a class to handle the requests, call handle and echo the response. Student will look for the Student.php class so make sure it&#8217;s available in your include paths. That&#8217;s it, hope you found this helpful. As a side note, I noticed Zend_Amf_Server has a method to addDirectory instead of adding each class separately. Hopefully this gets added to Zend_Json_Server at some point.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeyrivera.com/2011/zend_json_server-and-how-to-call-it-via-json-rpc-2-0/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Facebook Graph API App Easy w/ PHP SDK</title>
		<link>http://www.joeyrivera.com/2010/facebook-graph-api-app-easy-w-php-sdk/</link>
		<comments>http://www.joeyrivera.com/2010/facebook-graph-api-app-easy-w-php-sdk/#comments</comments>
		<pubDate>Thu, 02 Dec 2010 20:14:56 +0000</pubDate>
		<dc:creator>Joey</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[app]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[sdk]]></category>

		<guid isPermaLink="false">http://www.joeyrivera.com/?p=642</guid>
		<description><![CDATA[NOTE: This post was written using Facebook&#8217;s PHP SDK version 2.1.2. Since this post was made, the PHP SDK has changed and some of the process that are explained below may have changed as well. At some point I&#8217;ll have to revisit this post and update it but at this time just keep in mind [...]]]></description>
			<content:encoded><![CDATA[<p>NOTE: This post was written using Facebook&#8217;s PHP SDK version 2.1.2. Since this post was made, the PHP SDK has changed and some of the process that are explained below may have changed as well. At some point I&#8217;ll have to revisit this post and update it but at this time just keep in mind of the above.</p>
<p>As promised, here is a post (similar to my Twitter API post) on using the Facebook API. There are many reason why one would want to access the Facebook API &#8211; maybe to create a mobile app that lets you post photos to your Facebook albums, or maybe you just want to show your last few Facebook status updates on your blog; what ever the reason may be, Facebooks Graph API mixed in with their PHP SDK makes it really easy to accomplish this.</p>
<h2>Objectives</h2>
<ul>
<li>Setup our environment</li>
<li>Register an app on Facebook</li>
<li>Understand the authentication process and extended parameters</li>
<li>Understand Graph API</li>
<li>Retrieve our latest status updates</li>
<li>Add a new status update</li>
<li>Retrieve our photos from our albums</li>
<li>Add a new photo<span id="more-642"></span></li>
</ul>
<h2>Setup our Environment</h2>
<p>You have two options here, you can access my github and download this project with all required files and library or you can follow this tutorial step by step &#8211; it&#8217;s really up to you. If you want to download all the files ahead of time, you can get them at this github <a title="github repo for this project" href="https://github.com/joeyrivera/Facebook-Graph-API-Examples" target="_blank">repo</a>. If you are going step by step, first create a folder (I&#8217;m calling mine facebook) in your server where you want this site, next create a folder named library in the root of this site, and finally add the following two files facebook.php and fb_ca_chain_bundle.crt in the library folder that you can get from the Facebook PHP SDK repo at: <a title="Facebook PHP SDK repo" href="https://github.com/facebook/php-sdk/tree/master/src/" target="_blank">https://github.com/facebook/php-sdk/tree/master/src/</a>.</p>
<h2>Register an App on Facebook</h2>
<p>I&#8217;m making the assumption you already have a facebook account and if you don&#8217;t, first create one. To create an app on Facebook, you first need to confirm your account by giving Facebook a phone number where they can send you a code. This may be a new process since I don&#8217;t remember having to do this a few months ago. Go to <a href="http://developers.facebook.com/setup">http://developers.facebook.com/setup</a> and if your account is not verified, you&#8217;ll be prompted to add the information mentioned above. After verifying your accout, you&#8217;ll be taken to the &#8216;Create an Application&#8217; page.</p>
<div class="wp-caption aligncenter" style="width: 355px"><img title="Create App" src="/blog_files/642/createapp.gif" alt="Create App" width="345" height="369" /><p class="wp-caption-text">This is what the page should look like</p></div>
<p>Simply give your site a name and type in your site&#8217;s url and click create app. In my case I&#8217;m calling my app &#8216;Blog Test&#8217; and my site would be &#8216;http://www.joeyrivera.com/&#8217;. Next you will be prompted to type in a captcha and continue. Now you are done setting up your app, you see a screen like the following with your app id and app secret:</p>
<div class="wp-caption aligncenter" style="width: 338px"><img title="App Created" src="/blog_files/642/appcreated.gif" alt="App Created" width="328" height="113" /><p class="wp-caption-text">Here is your app info</p></div>
<h2>Authenticating and Extended Parameters</h2>
<p>Facebook uses OAuth for authenticating involving tokens being send back and forth but we don&#8217;t have to concern ourselves with the details &#8211; the Facebook PHP SDK does it all for us. It makes sure to send all the required information in the proper format so Facebook gets what it needs and sends us back what we need. You can read more about authenticating with Facebook at their <a title="Facebook Authentication" href="http://developers.facebook.com/docs/authentication/">site</a> and you can also read my <a title="Joey Rivera Twitter API" href="http://www.joeyrivera.com/2010/twitter-api-oauth-authentication-and-zend_oauth-tutorial/">Twitter API post</a> that discusses the OAuth in a little more detail if you are interested. The SDK also takes care of handling all API calls for us so we only have to give it the resource we are trying to access, let it know if we want to do a get or post, and finally give it all the parameters required for the call.</p>
<p>Extended Parameters is an interesting way of restricting access to an app (I&#8217;m using the term app to describe what we are building here) through the API. Unless a user allows access to certain parts of their account, an app will not be able to modify nor read parts of the account even if they are authenticated. Extended Parameters need to be explicitly assigned at the point of authenticating. When the user is taken to Facebook and asked to allow access to their account, the user is also presented with all the various parts of their account this app wants to interact with. Here is an example of what the user will see when trying to authenticate with our app:</p>
<div class="wp-caption aligncenter" style="width: 578px"><a href="All requested permissions"><img title="Extended Permissions" src="/blog_files/642/permissions.gif" alt="" width="568" height="410" /></a><p class="wp-caption-text">Extended Permissions</p></div>
<p>The first one in the screen shot is the default requested permission to access all the users basic information. The other three we need to accomplish our goals set including: read and post status updates as well as view and post photos. <a title="Facebook Extended Permissions" href="http://developers.facebook.com/docs/authentication/permissions">Here</a> you can see a complete list of all the available extended permissions. If you access that link, you&#8217;ll see there are a lot of permissions. I recommend taking some time reading through their descriptions to get a better understanding of the kinds of things you can do with the API. There have been times where I&#8217;ve tried to do something with an app and the Facebook Graph API without success only to find out I hadn&#8217;t requested a required permission for that to work.</p>
<p>Time for code, what we are about to do is to create an array with our app id and app secret to feed to the Facebook class when we instantiate it. Next, we are going to check to see if we are authenticated and if not, redirect us to the Facebook authenticate page passing it the extended parameters we want access to. Below is the code for the config.php file. Download form my <a title="Joey Rivera GitHub Repository" href="https://github.com/joeyrivera/Facebook-Graph-API-Examples">repository</a> or create the file below on the root of your site:</p>
<h4>config.php</h4>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">require_once</span> <span class="st0">&#8216;library/facebook.php&#8217;</span>;</p>
<p><span class="re0">$app_id</span> = <span class="st0">&quot;yourappid&quot;</span>;<br />
<span class="re0">$app_secret</span> = <span class="st0">&quot;yourappsecret&quot;</span>;</p>
<p><span class="re0">$facebook</span> = <span class="kw2">new</span> Facebook<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;appId&#8217;</span> =&gt; <span class="re0">$app_id</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;secret&#8217;</span> =&gt; <span class="re0">$app_secret</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;cookie&#8217;</span> =&gt; <span class="kw2">true</span><br />
<span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p><span class="kw1">if</span><span class="br0">&#40;</span><a href="http://www.php.net/is_null"><span class="kw3">is_null</span></a><span class="br0">&#40;</span><span class="re0">$facebook</span>-&gt;<span class="me1">getUser</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">&quot;Location:{$facebook-&gt;getLoginUrl(array(&#8216;req_perms&#8217; =&gt; &#8216;user_status,publish_stream,user_photos&#8217;))}&quot;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/exit"><span class="kw3">exit</span></a>;<br />
<span class="br0">&#125;</span></div>
<p>Make sure to update the app_id and app_secret variables with the information you received from Facebook after registering your app. Let me give you a quick explanation of the code. First we include the facebook.php file that we downloaded from the Facebook PHP SDK github repository. Then we instantiate a facebook instance passing it the app id, app secret, and tell it to use cookies to store the session/token information after authenticating. Next we call getUser() to see if we are already authenticated &#8211; null means we are not, else we receive the users id. If we are not authenticated, we redirect the user to Facebook to authenticate. The url is provided to us from the getLoginUrl method. We are sending that method an array with a key req_perms (required permissions) and the value is a comma delimited list of all the extended permissions we want access to. Again, a complete list of all permissions can be found at <a title="Facebook Extended Permissiosn" href="http://developers.facebook.com/docs/authentication/permissions">Facebooks docs</a>.</p>
<p>Go ahead and try to access this page in your browser. You should be immediately redirected to Facebook. If you are not already logged in with your Facebook account, you&#8217;ll first be asked to log in with the user which you want your app to access. Next you&#8217;ll see the &#8216;Request for Permission&#8217; page, click allow and you&#8217;ll be taken back to the config.php page on your server. This process takes you back to the page which initiated the authentication which was the config.php page. We have now successfully authenticated with Facebook.</p>
<p>In testing your app, you may decide you need more or less extended permissions. While you are authenticated with Facebook and have your token stored in a cookie, you won&#8217;t be able to re-authenticate using this code since you&#8217;ll be getting a User object back so you have a few options: You can close your browser, clear cookies, and authenticate again after modifying your code; You can force another echo or header redirect to the getLoginUrl() again with the new parameters; or you can log into your Facebook account (the user you authenticated), click on account on the top right, privacy settings, and in the bottom left you&#8217;ll see application and websites, click on edit your settings. Under applications you use, you should see your app listed, click on edit settings. Finally click on the &#8216;x&#8217; delete button to delete your app from the list. This will now remove your app from this users app list and won&#8217;t allow the app to access this account until the user authenticates again.</p>
<h2>Graph API</h2>
<p>This was confusing to me at first, specially since I keep rushing my project instead of taking my time to carefully look and read over the documents to truly understand what&#8217;s going on. Here is the <a title="Facebook Graph API Overview" href="http://developers.facebook.com/docs/api">Facebook Graph API overview</a> if you would like to read that first but I&#8217;ll try to summarize it here. Graph API allows you to call various resources all of which will be returned to you as JSON objects. You&#8217;ll have to spend some time at the <a title="Facebook Graph API References" href="http://developers.facebook.com/docs/reference/api/">Graph API References</a> page to understand the different objects available, parameters they have, and what the required extended permissions are to access them. I&#8217;ll try to explain connections in a sec.</p>
<p>Lets talk about the <a title="Facebook Graph API User" href="http://developers.facebook.com/docs/reference/api/user">User</a> object first. If you look at the reference page for user, you&#8217;ll see that to call the user object (the user who is authenticated by the app) you would call the graph api url with a &#8216;/me&#8217; at the end. If the call is made successfully, you&#8217;ll receive a JSON object with all the possible properties defined in the reference page (if they are set). Here is a quick example.</p>
<h4>user.php</h4>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">require_once</span> <span class="st0">&#8216;config.php&#8217;</span>;<br />
<span class="re0">$me</span> = <span class="re0">$facebook</span>-&gt;<span class="me1">api</span><span class="br0">&#40;</span><span class="st0">&#8216;/me&#8217;</span><span class="br0">&#41;</span>;<br />
<a href="http://www.php.net/var_dump"><span class="kw3">var_dump</span></a><span class="br0">&#40;</span><span class="re0">$me</span><span class="br0">&#41;</span>;</div>
<p>If you run this code you get something like this:</p>
<div class="wp-caption aligncenter" style="width: 596px"><img title="User Object" src="/blog_files/642/user.gif" alt="User Object" width="586" height="379" /><p class="wp-caption-text">This is my user object and properties.</p></div>
<p>Once you have the object, you can access it&#8217;s properties or do what you need with it. Now I&#8217;ll try to explain connections. If you look at the user reference page again and scroll down, you&#8217;ll see a connections section. These are the objects you can get that belong to this user. To access those objects you would call the url /me/object you want. For example, if you want to get this users albums, you would call /me/albums and this would return an array of album objects but remember to meet the required permission. For your app to access /me/albums, you need the user_photos extended permission (which we set in our config.php file).</p>
<p>So a connection is just a bridge between one object an another. Another example would be lets say we do as we did above and get all the users albums. Now we want to see all the photos inside each album. If you look at the <a title="Facebook Graph API Album Object" href="http://developers.facebook.com/docs/reference/api/album">album</a> object, you&#8217;ll notice that under connections is photos which returns an array of photo objects. That is what we would call to get all the photos in that album for each album and you&#8217;ll see the code to do just this later on.</p>
<h2>Get Status Posts</h2>
<p>Create the following page and I&#8217;ll explain the code below.</p>
<h4>status.php</h4>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">require_once</span> <span class="st0">&#8216;config.php&#8217;</span>;</p>
<p><span class="co1">// show statuses</span><br />
<span class="re0">$statuses</span> = <span class="re0">$facebook</span>-&gt;<span class="me1">api</span><span class="br0">&#40;</span><span class="st0">&#8216;/me/statuses&#8217;</span><span class="br0">&#41;</span>;<br />
<span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$statuses</span><span class="br0">&#91;</span><span class="st0">&#8216;data&#8217;</span><span class="br0">&#93;</span> <span class="kw1">as</span> <span class="re0">$status</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="re0">$status</span><span class="br0">&#91;</span><span class="st0">&quot;message&quot;</span><span class="br0">&#93;</span>, <span class="st0">&quot;&lt;br /&gt;&quot;</span>;<br />
<span class="br0">&#125;</span></div>
<p>First include the config.php file we created earlier (you&#8217;ll include this in all the other pages as well). The api method is what we&#8217;ll be using every time we need to call a resource and it can take in three parameters: the resource, get/post (defaults to get), and params (if any). In this case we want to call the statuses connection in the <a title="Facebook Graph API User Object" href="http://developers.facebook.com/docs/reference/api/user">user</a> object which returns and array of status messages. After receiving the messages, we loop through each and echo them out. If you want to see all the properties of each status, just do a var_dump on each status. That&#8217;s it, now the next example.</p>
<h2>Add New Status</h2>
<p>Here we are doing something a bit different, we are publishing to Facebook and for more info you can look at the <a title="Facebook Graph API Overview" href="http://developers.facebook.com/docs/api">Facebook Graph API Overview</a> in the publishing section. We want to create a new post so lets look at the <a title="Facebook Graph API Post Object" href="http://developers.facebook.com/docs/reference/api/post">reference guide</a> for information on post and its properties. Scroll down to the publishing section and notice we need the publish_stream extended property and you can see all the different properties that this object supports. I&#8217;m personally a bit confused on what is considered a required property and what it not, is seems nothing is required but for this example we want to submit a post with a message.</p>
<h4>status_add.php</h4>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">require_once</span> <span class="st0">&#8216;config.php&#8217;</span>;</p>
<p><span class="co1">// add a status message</span><br />
<span class="re0">$status</span> = <span class="re0">$facebook</span>-&gt;<span class="me1">api</span><span class="br0">&#40;</span><span class="st0">&#8216;/me/feed&#8217;</span>, <span class="st0">&#8216;POST&#8217;</span>, <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st0">&#8216;message&#8217;</span> =&gt; <span class="st0">&#8216;This post came from my app.&#8217;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p><a href="http://www.php.net/var_dump"><span class="kw3">var_dump</span></a><span class="br0">&#40;</span><span class="re0">$status</span><span class="br0">&#41;</span>;</div>
<p>This is all the code required to make a post! It&#8217;s that easy. We call the api method, tell it we want to call the /me/feed connection, set method to post, and finally pass an array with the properties we want to set &#8211; in this case just the message property. If you wanted to set other properties, you would have set them in that array such as &#8216;link&#8217; =&gt; &#8216;http://link.to.something&#8217;, etc. If the call is successfully, you&#8217;ll receive an id back which is the id for the new post you just created. Run this code and if all goes well, you should be able to go check our the users Facebook wall and see this latest post. I don&#8217;t think you can post the same message twice (unless I&#8217;m confusing Facebook with Twitter) so if you try it twice and it doesn&#8217;t work, that might be why.</p>
<h2>View Photos From Albums</h2>
<p>In this example, we want to get all the different albums for our user. Then we need to loop through each album and make a second call that will return all the photos for each album.</p>
<h4>photos.php</h4>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">require_once</span> <span class="st0">&#8216;config.php&#8217;</span>;</p>
<p><span class="co1">// get albums</span><br />
<span class="re0">$albums</span> = <span class="re0">$facebook</span>-&gt;<span class="me1">api</span><span class="br0">&#40;</span><span class="st0">&#8216;/me/albums&#8217;</span><span class="br0">&#41;</span>;</p>
<p><span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$albums</span><span class="br0">&#91;</span><span class="st0">&#8216;data&#8217;</span><span class="br0">&#93;</span> <span class="kw1">as</span> <span class="re0">$album</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// get all photos for album</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$photos</span> = <span class="re0">$facebook</span>-&gt;<span class="me1">api</span><span class="br0">&#40;</span><span class="st0">&quot;/{$album['id']}/photos&quot;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$photos</span><span class="br0">&#91;</span><span class="st0">&#8216;data&#8217;</span><span class="br0">&#93;</span> <span class="kw1">as</span> <span class="re0">$photo</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">&quot;&lt;img src=&#8217;{$photo['source']}&#8217; /&gt;&quot;</span>, <span class="st0">&quot;&lt;br /&gt;&quot;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
<p>Here we call the albums connection on user to get all the album objects. We loop through each and for each album get the album id to then call the <a title="Facebook Graph API Photo Object" href="http://developers.facebook.com/docs/reference/api/photo">photo</a> connection on the <a title="Facebook Graph API Album Object" href="http://developers.facebook.com/docs/reference/api/album">album</a> object. If this sounds confusing just let me know and I&#8217;ll try to explain this further. When I think of connections I think of joins in a db. It&#8217;s like saying I want to join the albums table for the user in the user table therefor retrieving all rows in ablum for a specific user.</p>
<h2>Add Photo</h2>
<p>In the interest of time and complexity, I&#8217;m just going to add a photo without specifying an album. By doing this, Facebook will automatically create a new album to add this photo to. Just know that you can specify an album to add photos directly too if needed.</p>
<h4>photos_add.php</h4>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">require_once</span> <span class="st0">&#8216;config.php&#8217;</span>;</p>
<p><span class="re0">$img</span> = <a href="http://www.php.net/realpath"><span class="kw3">realpath</span></a><span class="br0">&#40;</span><span class="st0">&quot;C:<span class="es0">\\</span>path<span class="es0">\\</span>to<span class="es0">\\</span>file.jpg&quot;</span><span class="br0">&#41;</span>;</p>
<p><span class="co1">// allow uploads</span><br />
<span class="re0">$facebook</span>-&gt;<span class="me1">setFileUploadSupport</span><span class="br0">&#40;</span><span class="st0">&quot;http://&quot;</span> . <span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st0">&#8216;SERVER_NAME&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</p>
<p><span class="co1">// add a status message</span><br />
<span class="re0">$photo</span> = <span class="re0">$facebook</span>-&gt;<span class="me1">api</span><span class="br0">&#40;</span><span class="st0">&#8216;/me/photos&#8217;</span>, <span class="st0">&#8216;POST&#8217;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;source&#8217;</span> =&gt; <span class="st0">&#8216;@&#8217;</span> . <span class="re0">$img</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;message&#8217;</span> =&gt; <span class="st0">&#8216;This photo came from my app.&#8217;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><br />
<span class="br0">&#41;</span>;</p>
<p><a href="http://www.php.net/var_dump"><span class="kw3">var_dump</span></a><span class="br0">&#40;</span><span class="re0">$photo</span><span class="br0">&#41;</span>;</div>
<p>I choose this example for people that want to understand how to post a file through a service like this. First lets start at the top. We need to specify the path to the image we want to upload so change that path to where you file resides. Usually this would be the tmp path for a photo just uploaded to your server via $_FILE. Next we need to tell facebook to allow uploading of a file. I didn&#8217;t investigate that method much other then the comments said to specify the server so I use SERVER_NAME to signify this server. Next we make the call. We are calling /me/photos since that&#8217;s what is specified in the <a title="Facebook Graph API Photos Object" href="http://developers.facebook.com/docs/reference/api/photo">photos reference page</a> under publishing. We are passing two parameters, message is the text that will show up with the image and source is the image we want to upload. Notice there is an @ before the path to the image. This is because we want to post the contents of the file and not pass a string to where the file is. Run this code and if all worked well, you&#8217;ll see this image and an new album in your users Facebook page.</p>
<h2>Conclusion</h2>
<p>If all went well, your users Facebook wall should look something like this:</p>
<div class="wp-caption aligncenter" style="width: 543px"><img title="Done" src="/blog_files/642/done.gif" alt="Done" width="533" height="430" /><p class="wp-caption-text">My test users Facebook wall</p></div>
<p>I hope that with this, you have a good understanding on how Facebook&#8217;s Graph API works. Start trying to call other objects and play with different extended permissions. The Facebook team did a great job in providing us with the PHP SDK to make this so extremely easy so thumbs up to them. If you have any question/comments, just post them below.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeyrivera.com/2010/facebook-graph-api-app-easy-w-php-sdk/feed/</wfw:commentRss>
		<slash:comments>278</slash:comments>
		</item>
		<item>
		<title>Twitter API, OAuth Authentication, and Zend_Oauth Tutorial</title>
		<link>http://www.joeyrivera.com/2010/twitter-api-oauth-authentication-and-zend_oauth-tutorial/</link>
		<comments>http://www.joeyrivera.com/2010/twitter-api-oauth-authentication-and-zend_oauth-tutorial/#comments</comments>
		<pubDate>Mon, 25 Oct 2010 20:52:03 +0000</pubDate>
		<dc:creator>Joey</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[authentication]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[zend_oauth]]></category>

		<guid isPermaLink="false">http://www.joeyrivera.com/?p=617</guid>
		<description><![CDATA[I recently had to work on a project that required me to interact with the Twitter API. I had done this before so I wasn&#8217;t expecting anything different until I remembered that Twitter had changed their API to start using OAuth for authentication. If you are not familiar with OAuth, it&#8217;s a secure way of [...]]]></description>
			<content:encoded><![CDATA[<p>I recently had to work on a project that required me to interact with the Twitter API. I had done this before so I wasn&#8217;t expecting anything different until I remembered that Twitter had changed their API to start using OAuth for authentication. If you are not familiar with OAuth, it&#8217;s a secure way of authenticating without requiring a user to submit their username and password to third-parties &#8211; you can read more about it at <a title="OAuth Website" href="http://oauth.net/">OAuth</a>. There are lots of resources online that talk about this in detail but I wasn&#8217;t able to find one that explained the entire process in a way that made sense. Hopefully this post will give you everything you need to get started with the Twitter API. I&#8217;m going to go through the steps required to make this work without using the entire zend framework.</p>
<h2>Objective</h2>
<p>This tutorial will go step-by-step in explaining how to create a small PHP application that can interact with the Twitter API. Our goal is to:</p>
<ul>
<li>Authenticate</li>
<li>Display our latest tweets</li>
<li>Post new tweets from PHP</li>
<li>Display the last few times our account was mentioned</li>
</ul>
<p>The only assumptions at this point (other than knowing PHP) is that you have a twitter account and the zend framework library <a title="Get the Zend Framework" href="http://framework.zend.com/download/latest">downloaded</a>. We won&#8217;t be using the entire framework, just some of the files as standalone modules.</p>
<h2>Registering An App</h2>
<p>The first step in being able to communicate with the Twitter API is to register an app in their system so you can receive all the necessary keys to authenticate with OAuth. Go to <a title="Twitter Developer" href="http://dev.twitter.com/">dev.twitter.com</a> and log in with your Twitter account. Now click on &#8216;register an app&#8217; (if that link is not visible then click on &#8216;your apps&#8217; on the top right and then click on &#8216;register an app&#8217; in the next page). These are the values I put in the form on the next page for my app. Feel free to follow along. I&#8217;ll explain the important inputs.</p>
<p><strong>Application:</strong> Joey&#8217;s Blog Example<br />
<strong>Description:</strong> Twitter PHP App<br />
<strong>Application Website:</strong> http://www.joeyrivera.com<br />
<strong>Organization:</strong> None<br />
<strong>Application Type:</strong> Browser<br />
<strong>Callback URL:</strong> http://www.joeyrivera.com/twitter/callback.php<br />
<strong>Default Access Type:</strong> Read &amp; Write<span id="more-617"></span></p>
<p>Most of the above are self-explanatory but let me explain callback since it&#8217;s an important one. Before we can talk to Twitter, we need to authenticate to get a token from Twitter. Once we have our token, we can start calling the API. During authentication, we are actually going to leave our application and go to Twitters website where the user will have to enter their twitter credentials. After the user allows our application and is done authenticating, Twitter will redirect the user back to our applications callback url. We haven&#8217;t created the file yet, but point back to a file called &#8216;callback.php&#8217; where you plan on putting this file. We will create this file later. (I mentioned users don&#8217;t have to give third-parties their user/pass but they still have to let Twitter know it&#8217;s ok for this app to access their account.)</p>
<p>Enter the captcha and register. At this point we have successfully registered our app that can now start communicating with the Twitter API.</p>
<h2>Authenticating</h2>
<p>To authenticate using Zend_Oauth we need to create a consumer object. The consumer needs an array with the following parameters:</p>
<ul>
<li>callbackUrl: Same as the one used during &#8216;registering an app&#8217;.</li>
<li>siteUrl: The url where the token request will take place. In this case: &#8216;http://twitter.com/oauth&#8217;.</li>
<li>consumerKey: This value is assigned to you after registering your app. To get this value, log into dev.twitter.com, go to your apps, and select the app you just created during &#8216;registering an app&#8217; above. All your keys/secret and info will be listed on that page.</li>
<li>consumerSecret: same steps as consumerKey.</li>
</ul>
<p>We are going to be using the code from <a href="http://framework.zend.com/manual/en/zend.oauth.introduction.html">zend docs</a> with a couple minor tweaks or additions. The code is below:</p>
<h4>authenticate.php</h4>
<div class="dean_ch" style="white-space: wrap;"><a href="http://www.php.net/session_start"><span class="kw3">session_start</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><a href="http://www.php.net/set_include_path"><span class="kw3">set_include_path</span></a><span class="br0">&#40;</span><span class="st0">&#8216;/path/to/zend/library/1.10.8&#8242;</span><span class="br0">&#41;</span>;<br />
<span class="kw1">require</span> <span class="st0">&#8216;Zend/Oauth/Consumer.php&#8217;</span>;</p>
<p><span class="re0">$config</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">&#8216;callbackUrl&#8217;</span> =&gt; <span class="st0">&#8216;http://www.joeyrivera.com/twitter/callback.php&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;siteUrl&#8217;</span> =&gt; <span class="st0">&#8216;http://twitter.com/oauth&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;consumerKey&#8217;</span> =&gt; <span class="st0">&#8216;ASD234ADF34ADSF&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;consumerSecret&#8217;</span> =&gt; <span class="st0">&#8217;24GH789JSDFGDFG345098DF09873SDFSD&#8217;</span><br />
<span class="br0">&#41;</span>;</p>
<p><span class="re0">$consumer</span> = <span class="kw2">new</span> Zend_Oauth_Consumer<span class="br0">&#40;</span><span class="re0">$config</span><span class="br0">&#41;</span>;</p>
<p><span class="co1">// fetch a request token</span><br />
<span class="re0">$token</span> = <span class="re0">$consumer</span>-&gt;<span class="me1">getRequestToken</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><span class="co1">// persist the token to storage</span><br />
<span class="re0">$_SESSION</span><span class="br0">&#91;</span><span class="st0">&#8216;TWITTER_REQUEST_TOKEN&#8217;</span><span class="br0">&#93;</span> = <a href="http://www.php.net/serialize"><span class="kw3">serialize</span></a><span class="br0">&#40;</span><span class="re0">$token</span><span class="br0">&#41;</span>;</p>
<p><span class="co1">// redirect the user</span><br />
<span class="re0">$consumer</span>-&gt;<span class="me1">redirect</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
<p>Create a file and paste the above code in there and save your file as authenticate.php. Go back and modify the values of the $config array to use your callbackUrl, siteUrl, consumerKey, and consumerSecret. Also make sure to modify the include path to include your library folder where the zend framework resides (I&#8217;m using the framework version 1.10.8 for these examples).</p>
<p>Quick explanation of the code. First we start our session since we&#8217;ll be using a session variable to track the request token needed to create the access token later. Then we create a consumer and create the request token. Finally we call redirect on the consumer which sends us to twitter feeding it all the necessary information in the proper format for us to then authenticate. There is lots of magic going on behind the scene and for a better understanding on how the token and signature works read the OAuth docs. I personally find it much easier to use Zend_Oauth instead.</p>
<p>Now lets create the callback file, code is below:</p>
<h4>callback.php</h4>
<div class="dean_ch" style="white-space: wrap;"><a href="http://www.php.net/session_start"><span class="kw3">session_start</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><a href="http://www.php.net/set_include_path"><span class="kw3">set_include_path</span></a><span class="br0">&#40;</span><span class="st0">&#8216;/path/to/zend/library/1.10.8&#8242;</span><span class="br0">&#41;</span>;<br />
<span class="kw1">require</span> <span class="st0">&#8216;Zend/Oauth/Consumer.php&#8217;</span>;</p>
<p><span class="re0">$config</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">&#8216;callbackUrl&#8217;</span> =&gt; <span class="st0">&#8216;http://www.joeyrivera.com/twitter/callback.php&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;siteUrl&#8217;</span> =&gt; <span class="st0">&#8216;http://twitter.com/oauth&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;consumerKey&#8217;</span> =&gt; <span class="st0">&#8216;ASD234ADF34ADSF&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;consumerSecret&#8217;</span> =&gt; <span class="st0">&#8217;24GH789JSDFGDFG345098DF09873SDFSD&#8217;</span><br />
<span class="br0">&#41;</span>;</p>
<p><span class="re0">$consumer</span> = <span class="kw2">new</span> Zend_Oauth_Consumer<span class="br0">&#40;</span><span class="re0">$config</span><span class="br0">&#41;</span>;</p>
<p><span class="kw1">if</span> <span class="br0">&#40;</span>!<a href="http://www.php.net/empty"><span class="kw3">empty</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#41;</span> &amp;amp;&amp;amp; <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$_SESSION</span><span class="br0">&#91;</span><span class="st0">&#8216;TWITTER_REQUEST_TOKEN&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="re0">$token</span> = <span class="re0">$consumer</span>-&gt;<span class="me1">getAccessToken</span><span class="br0">&#40;</span><span class="re0">$_GET</span>, <a href="http://www.php.net/unserialize"><span class="kw3">unserialize</span></a><span class="br0">&#40;</span><span class="re0">$_SESSION</span><span class="br0">&#91;</span><span class="st0">&#8216;TWITTER_REQUEST_TOKEN&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="co1">// Now that we have an Access Token, we can discard the Request Token</span><br />
&nbsp; &nbsp; <span class="re0">$_SESSION</span><span class="br0">&#91;</span><span class="st0">&#8216;TWITTER_REQUEST_TOKEN&#8217;</span><span class="br0">&#93;</span> = <span class="kw2">null</span>;<br />
<span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="co1">// Mistaken request? Some malfeasant trying something?</span><br />
&nbsp; &nbsp; <a href="http://www.php.net/exit"><span class="kw3">exit</span></a><span class="br0">&#40;</span><span class="st0">&#8216;Invalid callback request. Oops. Sorry.&#8217;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="co1">// save token to file</span><br />
file_put_contents<span class="br0">&#40;</span><span class="st0">&#8216;token.txt&#8217;</span>, <a href="http://www.php.net/serialize"><span class="kw3">serialize</span></a><span class="br0">&#40;</span><span class="re0">$token</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
<p>Save this file as callback.php after modifying the $config variables and library path just like with authenticate.php. We are once again starting our session to be able to capture the &#8216;TWITTER_REQUEST_TOKEN&#8217; created in the previous step. Then we create the consumer again and check to make sure the session is there and that we received query string parameters from Twitter. If everything is as expected, we feed the consumer all the information and ask it for an access token. This is the token we need to track since it&#8217;s the token we need for any call our application makes to the Twitter API. Since we no longer need the request token, we can remove it from the session.</p>
<p>The last step is to save the token somewhere so we can reuse it and not have to authenticate again. Twitter&#8217;s access token does not expire (at least not now). This means, once we authenticate with Twitter, as long as we have our access token stored and accessible to us, our client will not have to authenticate again (assuming Twitter doesn&#8217;t change their mind later and adds an expiration to their tokens). For the purpose of this example, I&#8217;m storing this token in the file system. Another option is to store this value in the database, it&#8217;s really up to you where you want to put it. If you are saving it to the file system, make sure that file is writable by your application.</p>
<p>Both files are created so lets try it out. Go to your browser and access the authenticate.php file. When the page loads, you should be redirected to Twitter and asked to log in (unless you are already logged into Twitter). Enter your twitter account user/pass that you want to access and continue. Next you&#8217;ll be asked if you want to allow this application to access your account. Go ahead and click allow, then you&#8217;ll be taken to your callback.php url. At this point we have authorized, received our access token, and stored it. Now we are done with our first goal and ready for the good stuff.</p>
<h2>Using our Token</h2>
<p>Our next goal was to display our latest tweets so this will be our first example on how to use our token. Technically, this isn&#8217;t the best example as you don&#8217;t need to authenticate with Twitter to display public user tweets but you&#8217;ll still get to see how to make a call to the Twitter API using our token.</p>
<h4>show_tweets.php</h4>
<div class="dean_ch" style="white-space: wrap;"><a href="http://www.php.net/set_include_path"><span class="kw3">set_include_path</span></a><span class="br0">&#40;</span><span class="st0">&#8216;/path/to/zend/library/1.10.8&#8242;</span><span class="br0">&#41;</span>;<br />
<span class="kw1">require</span> <span class="st0">&#8216;Zend/Oauth/Consumer.php&#8217;</span>;</p>
<p><span class="re0">$config</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">&#8216;callbackUrl&#8217;</span> =&gt; <span class="st0">&#8216;http://www.joeyrivera.com/twitter/callback.php&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;siteUrl&#8217;</span> =&gt; <span class="st0">&#8216;http://twitter.com/oauth&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;consumerKey&#8217;</span> =&gt; <span class="st0">&#8216;ASD234ADF34ADSF&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;consumerSecret&#8217;</span> =&gt; <span class="st0">&#8217;24GH789JSDFGDFG345098DF09873SDFSD&#8217;</span><br />
<span class="br0">&#41;</span>;</p>
<p><span class="re0">$token</span> = <a href="http://www.php.net/unserialize"><span class="kw3">unserialize</span></a><span class="br0">&#40;</span><a href="http://www.php.net/file_get_contents"><span class="kw3">file_get_contents</span></a><span class="br0">&#40;</span><span class="st0">&#8216;token.txt&#8217;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p><span class="re0">$client</span> = <span class="re0">$token</span>-&gt;<span class="me1">getHttpClient</span><span class="br0">&#40;</span><span class="re0">$config</span><span class="br0">&#41;</span>;<br />
<span class="re0">$client</span>-&gt;<span class="me1">setUri</span><span class="br0">&#40;</span><span class="st0">&#8216;http://twitter.com/statuses/user_timeline.json&#8217;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$client</span>-&gt;<span class="me1">setMethod</span><span class="br0">&#40;</span>Zend_Http_Client::<span class="me2">GET</span><span class="br0">&#41;</span>;<br />
<span class="re0">$client</span>-&gt;<span class="me1">setParameterGet</span><span class="br0">&#40;</span><span class="st0">&#8216;screen_name&#8217;</span>, <span class="st0">&#8216;joeyrivera&#8217;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$client</span>-&gt;<span class="me1">setParameterGet</span><span class="br0">&#40;</span><span class="st0">&#8216;count&#8217;</span>, <span class="st0">&#8217;10&#8242;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$response</span> = <span class="re0">$client</span>-&gt;<span class="me1">request</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><span class="re0">$tweets</span> = json_decode<span class="br0">&#40;</span><span class="re0">$response</span>-&gt;<span class="me1">getBody</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p><span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$tweets</span> <span class="kw1">as</span> <span class="re0">$tweet</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="re0">$tweet</span>-&gt;<span class="me1">text</span>, <span class="st0">&quot;&lt;br&gt;&quot;</span>;<br />
<span class="br0">&#125;</span></div>
<p>Paste the above code into a file called show_tweets.php and edit the configs yet again plus the library. At this point I&#8217;ll stop mentioning to edit the config and library &#8211; just remember to do the same with the next couple examples. First we get our token which we saved to a file during the callback phase. Then we create a client object, tell it what url to call, the method to use and pass two params to let the API know who&#8217;s tweets we want and how many tweets to return. Finally we tell the client to initiate the request and we display it when it comes back.</p>
<p>Where did I get the uri from? from Twitters docs page. Spend some time there learning all the different methods you can call and what the required parameters are. For <a title="User Timeline" href="http://dev.twitter.com/doc/get/statuses/user_timeline">user_timeline</a> (which is what we want to get our latest tweets) we need to call the uri used above. The last part, the .json at the end tells Twitter that we want a JSON encoded response back which is why we need to do a json_decode on the body to view it. You could have used .xml if you wanted an xml back instead. The docs for user_timeline also specify you need to do a get which is why we set it as a method and add the two get parameters. There are more parameters you can set if you like.</p>
<p>This is what I see when I run this page with my screen name:</p>
<pre>Flash, jQuery, and Php - what a pain you have all been to me today but I'm glad all is well again.
Put my car up on autotrader, check it out if you are in the market for a 2005 Subaru WRX STi or know someone who might: http://is.gd/g3tqv
someone owns a image rollover patent? http://arstechnica.com/tech-policy/news/2010/10/patent-troll-takes-over-the-web-can-it-be-stopped.ars
Microsoft has the best commercials! http://holykaw.alltop.com/microsoft-pokes-fun-at-smartphone-users-in-ne
Finally got oAuth working to post to Twitter from PHP.
Accidentally found this very cool video by RefinedData http://refineddata.com/products/refinedtraining/index.php
You guys have recommendations on course authoring tools like articulate/captivate that don't have a player. Just a place to create content?
Cool story on YouTube instant http://www.feross.org/youtube-instant-media-frenzy/ Congrats to Feross on the accomplishment.
After driving a Z06 Corvette, I have become a believer of American muscle. STi was fun but just doesn't compare to a Z06.
Been week since we paid for Adobe developer support license and we are still not closer to solving our problem. Hoping to make progress soon</pre>
<p>Now lets submit a tweet.</p>
<h4>submit_tweet.php</h4>
<div class="dean_ch" style="white-space: wrap;"><a href="http://www.php.net/set_include_path"><span class="kw3">set_include_path</span></a><span class="br0">&#40;</span><span class="st0">&#8216;/path/to/zend/library/1.10.8&#8242;</span><span class="br0">&#41;</span>;<br />
<span class="kw1">require</span> <span class="st0">&#8216;Zend/Oauth/Consumer.php&#8217;</span>;</p>
<p><span class="re0">$config</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">&#8216;callbackUrl&#8217;</span> =&gt; <span class="st0">&#8216;http://www.joeyrivera.com/twitter/callback.php&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;siteUrl&#8217;</span> =&gt; <span class="st0">&#8216;http://twitter.com/oauth&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;consumerKey&#8217;</span> =&gt; <span class="st0">&#8216;ASD234ADF34ADSF&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;consumerSecret&#8217;</span> =&gt; <span class="st0">&#8217;24GH789JSDFGDFG345098DF09873SDFSD&#8217;</span><br />
<span class="br0">&#41;</span>;</p>
<p><span class="re0">$token</span> = <a href="http://www.php.net/unserialize"><span class="kw3">unserialize</span></a><span class="br0">&#40;</span><a href="http://www.php.net/file_get_contents"><span class="kw3">file_get_contents</span></a><span class="br0">&#40;</span><span class="st0">&#8216;token.txt&#8217;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p><span class="re0">$client</span> = <span class="re0">$token</span>-&gt;<span class="me1">getHttpClient</span><span class="br0">&#40;</span><span class="re0">$config</span><span class="br0">&#41;</span>;<br />
<span class="re0">$client</span>-&gt;<span class="me1">setUri</span><span class="br0">&#40;</span><span class="st0">&#8216;http://twitter.com/statuses/update.json&#8217;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$client</span>-&gt;<span class="me1">setMethod</span><span class="br0">&#40;</span>Zend_Http_Client::<span class="me2">POST</span><span class="br0">&#41;</span>;<br />
<span class="re0">$client</span>-&gt;<span class="me1">setParameterPost</span><span class="br0">&#40;</span><span class="st0">&#8216;status&#8217;</span>, <span class="st0">&#8216;I hope to get my blog post on Twitter API with Zend_Oauth up in the next day.&#8217;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$response</span> = <span class="re0">$client</span>-&gt;<span class="me1">request</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><span class="re0">$data</span> = json_decode<span class="br0">&#40;</span><span class="re0">$response</span>-&gt;<span class="me1">getBody</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="re0">$data</span>-&gt;<span class="me1">text</span>;</div>
<p>The code is very similar. The resource we want to call this time is <a title="Statuses/Update" href="http://dev.twitter.com/doc/post/statuses/update">statuses/update</a>. It requires a post method so we use POST and setParameterPost instead of GET. The one required param is status &#8211; set that to the string you want to tweet and run this page. Now go check your tweeter account and you should have that status show up. Make sure the string you pass is 140 characters or less. Also, twitter won&#8217;t allow you to submit two identical statuses so if you are testing this code and it&#8217;s not working, make sure you are sending a unique string.</p>
<p>Finally we&#8217;ll create one last example that displays the last 5 mentions of our twitter account.</p>
<h4>mentioned_tweet.php</h4>
<div class="dean_ch" style="white-space: wrap;"><a href="http://www.php.net/set_include_path"><span class="kw3">set_include_path</span></a><span class="br0">&#40;</span><span class="st0">&#8216;/path/to/zend/library/1.10.8&#8242;</span><span class="br0">&#41;</span>;<br />
<span class="kw1">require</span> <span class="st0">&#8216;Zend/Oauth/Consumer.php&#8217;</span>;</p>
<p><span class="re0">$config</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">&#8216;callbackUrl&#8217;</span> =&gt; <span class="st0">&#8216;http://www.joeyrivera.com/twitter/callback.php&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;siteUrl&#8217;</span> =&gt; <span class="st0">&#8216;http://twitter.com/oauth&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;consumerKey&#8217;</span> =&gt; <span class="st0">&#8216;ASD234ADF34ADSF&#8217;</span>,<br />
&nbsp; &nbsp; <span class="st0">&#8216;consumerSecret&#8217;</span> =&gt; <span class="st0">&#8217;24GH789JSDFGDFG345098DF09873SDFSD&#8217;</span><br />
<span class="br0">&#41;</span>;</p>
<p><span class="re0">$token</span> = <a href="http://www.php.net/unserialize"><span class="kw3">unserialize</span></a><span class="br0">&#40;</span><a href="http://www.php.net/file_get_contents"><span class="kw3">file_get_contents</span></a><span class="br0">&#40;</span><span class="st0">&#8216;token.txt&#8217;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p><span class="re0">$client</span> = <span class="re0">$token</span>-&gt;<span class="me1">getHttpClient</span><span class="br0">&#40;</span><span class="re0">$config</span><span class="br0">&#41;</span>;<br />
<span class="re0">$client</span>-&gt;<span class="me1">setUri</span><span class="br0">&#40;</span><span class="st0">&#8216;http://twitter.com/statuses/mentions.json&#8217;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$client</span>-&gt;<span class="me1">setMethod</span><span class="br0">&#40;</span>Zend_Http_Client::<span class="me2">GET</span><span class="br0">&#41;</span>;<br />
<span class="re0">$client</span>-&gt;<span class="me1">setParameterGet</span><span class="br0">&#40;</span><span class="st0">&#8216;count&#8217;</span>, <span class="st0">&#8217;5&#8242;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$response</span> = <span class="re0">$client</span>-&gt;<span class="me1">request</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><span class="re0">$tweets</span> = json_decode<span class="br0">&#40;</span><span class="re0">$response</span>-&gt;<span class="me1">getBody</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p><span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$tweets</span> <span class="kw1">as</span> <span class="re0">$tweet</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="re0">$tweet</span>-&gt;<span class="me1">text</span>, <span class="st0">&quot;&lt;br&gt;&quot;</span>;<br />
<span class="br0">&#125;</span></div>
<p>The <a title="Mentions" href="http://dev.twitter.com/doc/get/statuses/mentions">mentions</a> resource uses GET and doesn&#8217;t require any parameter. I&#8217;m passing a count of 5 so you don&#8217;t get too much back. Here is what I see when I run this page:</p>
<pre>heads up! @mosesngone and @joeyrivera consuming Web Services Nov 4th @atlantaphp #atlantaphp http://meetu.ps/3Rbt</pre>
<h2>Conclusion</h2>
<p>Using Zend_Oauth it&#8217;s really easy to authenticate with OAuth and track your token. At that point calling the Twitter API is very simple. I want to thank the guys at Zend for making our lives so much easier with all these great modules. If you have any question feel free to ask. Hopefully you have all found this post very informative and helpful.</p>
<p>EDIT: Here is a similar post on using <a title="Joey Rivera Facebook Graph API and PHP SDK Post" href="http://www.joeyrivera.com/2010/facebook-graph-api-app-easy-w-php-sdk/">Facebooks Graph API with their PHP SDK</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeyrivera.com/2010/twitter-api-oauth-authentication-and-zend_oauth-tutorial/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>My car is for sale! 2005 Subaru WRX STi, 51,300 miles for $21,500 &#8211; SOLD!</title>
		<link>http://www.joeyrivera.com/2010/my-car-is-for-sale-2005-subaru-wrx-sti-51300-miles-for-21500/</link>
		<comments>http://www.joeyrivera.com/2010/my-car-is-for-sale-2005-subaru-wrx-sti-51300-miles-for-21500/#comments</comments>
		<pubDate>Fri, 15 Oct 2010 17:15:04 +0000</pubDate>
		<dc:creator>Joey</dc:creator>
				<category><![CDATA[My Car]]></category>
		<category><![CDATA[corvette]]></category>
		<category><![CDATA[sti]]></category>
		<category><![CDATA[subaru]]></category>
		<category><![CDATA[z06]]></category>

		<guid isPermaLink="false">http://www.joeyrivera.com/?p=611</guid>
		<description><![CDATA[Here is the link to autotrader with all the info: My car for sale. It&#8217;s a great car and I had a blast with it but I have bought a replacement, a Z06. The suby has a lot of mods, you can read about them all in my blog under &#8216;my-car&#8216; &#8211; pushed 450whp with [...]]]></description>
			<content:encoded><![CDATA[<p>Here is the link to autotrader with all the info: <a href="http://www.autotrader.com/fyc/vdp.jsp?ct=p&amp;car_id=288193683&amp;dealer_id=65766299&amp;car_year=2005&amp;rdm=1287156137263&amp;lastStartYear=1981&amp;model=IMPWRX&amp;num_records=25&amp;systime=&amp;make2=&amp;highlightFirstMakeModel=&amp;start_year=2005&amp;keywordsfyc=&amp;keywordsrep=&amp;engine=&amp;certified=&amp;body_code=0&amp;fuel=&amp;awsp=false&amp;search_type=both&amp;distance=25&amp;marketZipError=false&amp;search_lang=en&amp;sownerid=65504949&amp;showZipError=y&amp;make=SUB&amp;keywords_display=&amp;color=&amp;page_location=findacar::ispsearchform&amp;min_price=&amp;drive=&amp;default_sort=newsortbyprice_DESC&amp;seller_type=b&amp;max_mileage=&amp;style_flag=1&amp;sort_type=priceDESC&amp;address=30060&amp;advanced=&amp;end_year=2005&amp;doors=&amp;transmission=&amp;max_price=&amp;cardist=0&amp;standard=false">My car for sale</a>. It&#8217;s a great car and I had a blast with it but I have bought a replacement, a Z06. The suby has a lot of mods, you can read about them all in my blog under &#8216;<a href="http://www.joeyrivera.com/category/projects/my-car/">my-car</a>&#8216; &#8211; pushed 450whp with methanol. Contact me here or at autotrader for more questions. Here are some pictures of both:</p>
<p><img class="aligncenter size-full wp-image-441" title="Bofum1smll" src="http://jamesfleishel.files.wordpress.com/2010/09/bofum1smll.jpg?w=600&amp;h=284" alt="" width="600" height="284" /></p>
<p><span id="more-611"></span></p>
<p><img class="aligncenter size-full wp-image-451" title="Z06 3 smll" src="http://jamesfleishel.files.wordpress.com/2010/09/z06-3-smll.jpg?w=600&amp;h=450" alt="" width="600" height="450" /></p>
<p><img class="aligncenter size-full wp-image-449" title="STI 5 smll" src="http://jamesfleishel.files.wordpress.com/2010/09/sti-5-smll.jpg?w=600&amp;h=450" alt="" width="600" height="450" /></p>
<p><img style="-webkit-user-select: none;" src="http://jamesfleishel.files.wordpress.com/2010/09/z062smll.jpg" alt="" /></p>
<p>All the pics were taken by my brother-in-law, James. You can see the full gallery at his blog <a href="http://jamesfleishel.wordpress.com/2010/09/18/out-with-the-old-in-with-the-new/">James Fleishel</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeyrivera.com/2010/my-car-is-for-sale-2005-subaru-wrx-sti-51300-miles-for-21500/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to build an Adobe AIR Badge</title>
		<link>http://www.joeyrivera.com/2010/how-to-build-adobe-air-badge/</link>
		<comments>http://www.joeyrivera.com/2010/how-to-build-adobe-air-badge/#comments</comments>
		<pubDate>Wed, 04 Aug 2010 14:52:07 +0000</pubDate>
		<dc:creator>Joey</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[adobe]]></category>
		<category><![CDATA[badge]]></category>

		<guid isPermaLink="false">http://www.joeyrivera.com/?p=593</guid>
		<description><![CDATA[NOTE: This article was written with AIR 1.5 in mind. I can&#8217;t say if the following information will work as intended on AIR 2. If you already know how to build you own Adobe AIR badge, you won&#8217;t find much new information here. This post is more to inform users that you can in fact [...]]]></description>
			<content:encoded><![CDATA[<p>NOTE: This article was written with AIR 1.5 in mind. I can&#8217;t say if the following information will work as intended on AIR 2. If you already know how to build you own Adobe AIR badge, you won&#8217;t find much new information here. This post is more to inform users that you can in fact create your own AIR badge if you didn&#8217;t already know. When I first started working with AIR, I learned about the badge but as far as I was concerned, the badge was a black box who&#8217;s functionality was designed to remain mysterious.  The badge I used was the one <a title="Grant Skinner's website" href="http://www.gskinner.com/">Grant Skinner</a> created and you can get more information from <a title="About the Badge" href="http://www.adobe.com/devnet/air/articles/badge_for_air.html">Adobe</a> on how to use it. For a long time this badge worked well but finally the time has come where I need to make it behave a bit differently so I decided to do a bit of research.</p>
<p>After doing a few Google searches, I found a link to Adobe&#8217;s site with all the technical information on how to create your own AIR badge! I was completely surprised that I never even thought about the possibility that I could write my own badge&#8230; not sure what I was thinking. Nothing is more fun that reinventing the wheel right? After looking at the <a title="Adobe AIR 1.5 Badge" href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7e15.html">specifications</a>, I realized it wasn&#8217;t too bad and started to plan out a logical flow on how my badge was supposed to work.</p>
<h2>Requirements</h2>
<p>My current badge has the following issue: a user installs my app through the badge, every time after that point that the user comes back to the badge, they have to &#8216;install&#8217; the app again even thought it was already installed. Instead, I want the badge to sense if the application is installed and if so, launch it (I haven&#8217;t spend much time looking into Grants Badger app but I think it&#8217;ll let you do this as well if used correctly&#8230; I think). The logic for the new badge should be:</p>
<ol>
<li>Check if AIR is installed (If not, install)</li>
<li>Check if my app is installed (If not install)</li>
<li>Launch my app</li>
</ol>
<h2>Setup</h2>
<p>I&#8217;ll be using Flash CS3 since that&#8217;s what I have available to me for this tutorial and I am making the assumption you already know how to use Flash, understand ActionScript 3, and have an AIR app to test. Open Flash and create a new AS3 file and save it in some folder. Now attach a class called &#8216;Badge&#8217; to your file that extends MovieClip. Your class should look like the following:</p>
<div class="dean_ch" style="white-space: wrap;">package<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">import</span> flash.<span class="me1">display</span>.<span class="kw3">MovieClip</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">public</span> <span class="kw2">class</span> Badge <span class="kw3">extends</span> <span class="kw3">MovieClip</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">public</span> <span class="kw2">function</span> Badge<span class="br0">&#40;</span><span class="br0">&#41;</span>:<span class="kw3">void</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">trace</span><span class="br0">&#40;</span><span class="st0">&#8216;hi&#8217;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
<p>I added a trace in the constructor so I can make sure my class is working. When you test your badge you should see &#8216;hi&#8217; in your output window. Now we are ready to continue.<span id="more-593"></span></p>
<h2>air.swf</h2>
<p>Adobe created a file called air.swf that resides on their server at http://airdownload.adobe.com/air/browserapi/air.swf. This file contains all the functionality required to interact with AIR files through your badge. It can check to see if you have air installed on the local machine and install it, it can check to see if an air app is installed on the local machine and install it or launch. It does it all so the first step in creating a badge is to load this file so you can call it&#8217;s methods.</p>
<p>All we need to do is create a Loader instance, add an event listener to alert us when it&#8217;s done loading the air.swf file and call the load method passing in the url as a URLRequest. The code is below with all the required imports:</p>
<div class="dean_ch" style="white-space: wrap;">package<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">import</span> flash.<span class="me1">display</span>.<span class="kw3">MovieClip</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">import</span> flash.<span class="me1">events</span>.<span class="me1">Event</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">import</span> flash.<span class="me1">display</span>.<span class="me1">Loader</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">import</span> flash.<span class="me1">net</span>.<span class="me1">URLRequest</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">public</span> <span class="kw2">class</span> Badge <span class="kw3">extends</span> <span class="kw3">MovieClip</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> <span class="kw2">var</span> _air:<span class="kw3">Object</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">public</span> <span class="kw2">function</span> Badge<span class="br0">&#40;</span><span class="br0">&#41;</span>:<span class="kw3">void</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">var</span> loader:Loader = <span class="kw2">new</span> Loader<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loader.<span class="me1">contentLoaderInfo</span>.<span class="me1">addEventListener</span><span class="br0">&#40;</span>Event.<span class="me1">INIT</span>, airSwfLoaded<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loader.<span class="kw3">load</span><span class="br0">&#40;</span><span class="kw2">new</span> URLRequest<span class="br0">&#40;</span><span class="st0">&#8216;http://airdownload.adobe.com/air/browserapi/air.swf&#8217;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> <span class="kw2">function</span> airSwfLoaded<span class="br0">&#40;</span><span class="kw3">e</span>:Event<span class="br0">&#41;</span>:<span class="kw3">void</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>._air = <span class="kw3">e</span>.<span class="kw3">target</span>.<span class="me1">content</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">trace</span><span class="br0">&#40;</span><span class="kw3">this</span>._air.<span class="me1">getStatus</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
<p>Test the above code and in your output you should see one of the following <a title="Different status responses" href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7e15.html#WS5b3ccc516d4fbf351e63e3d118666ade46-7c98">status responses</a> (taken from Adobe&#8217;s site):</p>
<table border="1" cellspacing="0" cellpadding="4">
<thead>
<tr>
<th id="d17e28828" width="NaN%" valign="top">String value</th>
<th id="d17e28831" width="NaN%" valign="top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td width="NaN%" valign="top"><samp>&#8220;available&#8221;</samp></td>
<td width="NaN%" valign="top">The runtime can be installed on this computer but currently it is not installed.</td>
</tr>
<tr>
<td width="NaN%" valign="top"><samp>&#8220;unavailable&#8221;</samp></td>
<td width="NaN%" valign="top">The runtime cannot be installed on this computer.</td>
</tr>
<tr>
<td width="NaN%" valign="top"><samp>&#8220;installed&#8221;</samp></td>
<td width="NaN%" valign="top">The runtime is installed on this computer.</td>
</tr>
</tbody>
</table>
<h2>Handling the response</h2>
<p>Now that we have a status, we can tell the badge to handle it in the appropriate manner. The first status we need to handle is &#8216;available&#8217;. This means AIR is not installed on the machine but can be. By default, AIR needs to be installed before installing an AIR app so in this scenario, all we need to call is install on our app and AIR will be installed first automatically. Here is the <strong>tricky part</strong>, we can&#8217;t automatically call install on an AIR app, it is not allowed. <span style="text-decoration: underline;">You can only call install via a user initiated event such as a button click</span>.</p>
<p>If the status is unavailable, then we can&#8217;t do much other than let the user know they can&#8217;t install AIR on their machine. If the status is installed, then the user already has AIR installed and we need to check if they have our app installed. If they do not, we install it and let them launch it. If they do have it installed, we let them launch it. Below is the complete code that does all the above:</p>
<div class="dean_ch" style="white-space: wrap;">package<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">import</span> flash.<span class="me1">display</span>.<span class="kw3">MovieClip</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">import</span> flash.<span class="me1">events</span>.<span class="me1">Event</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">import</span> flash.<span class="me1">display</span>.<span class="me1">Loader</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">import</span> flash.<span class="me1">events</span>.<span class="me1">MouseEvent</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">import</span> flash.<span class="me1">net</span>.<span class="me1">URLRequest</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">import</span> fl.<span class="me1">controls</span>.<span class="kw3">Button</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">public</span> <span class="kw2">class</span> Badge <span class="kw3">extends</span> <span class="kw3">MovieClip</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> <span class="kw2">var</span> _air:<span class="kw3">Object</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> <span class="kw2">var</span> _myButton:<span class="kw3">Button</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> const APPID:<span class="kw3">String</span> = <span class="st0">&#8216;YOUAPPID&#8217;</span>; <span class="co1">// replace with your app id</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> const PUBID:<span class="kw3">String</span> = <span class="st0">&#8217;123123123123123123123123.1&#8242;</span>; <span class="co1">// replace with your publisher id</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> const APPURL:<span class="kw3">String</span> = <span class="st0">&#8216;http://www.yourdomain.com/YOUAIRAPP.air&#8217;</span>; <span class="co1">// replace with your app url</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> const APPRUNTIME:<span class="kw3">String</span> = <span class="st0">&#8217;1.5&#8242;</span>; <span class="co1">// I&#8217;m using 1.5 as a minimum requirement for this example</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> const AIRSWF:<span class="kw3">String</span> = <span class="st0">&#8216;http://airdownload.adobe.com/air/browserapi/air.swf&#8217;</span>; <span class="co1">// adobe&#8217;s file</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">public</span> <span class="kw2">function</span> Badge<span class="br0">&#40;</span><span class="br0">&#41;</span>:<span class="kw3">void</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">var</span> loader:Loader = <span class="kw2">new</span> Loader<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loader.<span class="me1">contentLoaderInfo</span>.<span class="me1">addEventListener</span><span class="br0">&#40;</span>Event.<span class="me1">INIT</span>, airSwfLoaded<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loader.<span class="kw3">load</span><span class="br0">&#40;</span><span class="kw2">new</span> URLRequest<span class="br0">&#40;</span><span class="kw3">this</span>.<span class="me1">AIRSWF</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>._myButton = <span class="kw2">new</span> <span class="kw3">Button</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>.<span class="me1">addChild</span><span class="br0">&#40;</span><span class="kw3">this</span>._myButton<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> <span class="kw2">function</span> airSwfLoaded<span class="br0">&#40;</span><span class="kw3">e</span>:Event<span class="br0">&#41;</span>:<span class="kw3">void</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>._air = <span class="kw3">e</span>.<span class="kw3">target</span>.<span class="me1">content</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">switch</span><span class="br0">&#40;</span><span class="kw3">this</span>._air.<span class="me1">getStatus</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;available&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// install app</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>.<span class="me1">installApp</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;unavailable&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// AIR not supported on this system</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;installed&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// check if app is installed</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>.<span class="me1">checkApp</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> <span class="kw2">function</span> checkApp<span class="br0">&#40;</span><span class="br0">&#41;</span>:<span class="kw3">void</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>._air.<span class="me1">getApplicationVersion</span><span class="br0">&#40;</span><span class="kw3">this</span>.<span class="me1">APPID</span>, <span class="kw3">this</span>.<span class="me1">PUBID</span>, checkAppCallback<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> <span class="kw2">function</span> checkAppCallback<span class="br0">&#40;</span><span class="kw3">version</span>:<span class="kw3">String</span><span class="br0">&#41;</span>:<span class="kw3">void</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">version</span> == <span class="kw2">null</span><span class="br0">&#41;</span> <span class="co1">// app is not installed</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>._myButton.<span class="me1">label</span> = <span class="st0">&quot;Install&quot;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>._myButton.<span class="me1">addEventListener</span><span class="br0">&#40;</span>MouseEvent.<span class="me1">CLICK</span>, installApp<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>._myButton.<span class="me1">label</span> = <span class="st0">&quot;Launch&quot;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>._myButton.<span class="me1">addEventListener</span><span class="br0">&#40;</span>MouseEvent.<span class="me1">CLICK</span>, launchApp<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> <span class="kw2">function</span> installApp<span class="br0">&#40;</span><span class="kw3">e</span>:Event = <span class="kw2">null</span><span class="br0">&#41;</span>:<span class="kw3">void</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>._air.<span class="me1">installApplication</span><span class="br0">&#40;</span><span class="kw3">this</span>.<span class="me1">APPURL</span>, <span class="kw3">this</span>.<span class="me1">APPRUNTIME</span>, <span class="kw2">new</span> <span class="kw3">Array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">private</span> <span class="kw2">function</span> launchApp<span class="br0">&#40;</span><span class="kw3">e</span>:Event<span class="br0">&#41;</span>:<span class="kw3">void</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">this</span>._air.<span class="me1">launchApplication</span><span class="br0">&#40;</span><span class="kw3">this</span>.<span class="me1">APPID</span>, <span class="kw3">this</span>.<span class="me1">PUBID</span>, <span class="kw2">new</span> <span class="kw3">Array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
<p>I added a button that depending on the status will display the appropriate label and call the corresponding method. If the status is available we know that my app is probably not installed (since AIR is not installed) so I tell my button to call the install app method. The install app method calls the installApplication method from the air.swf file and passes the following 3 paramets: the url of the app you are trying to install, the AIR runtime required for this app, and an array of parameters required for this app if any (make sure to modify those variables to match your needs). When a user clicks on the button, they will be asked to install AIR, install the AIR application, and allowed to start it.</p>
<p>If the status is installed, we call the check app method to see if our app is already installed on the users machine by seeing what version of the app is installed. A null version means that the app is not installed. If installed, our button will launch the application and if not, we call the install app method that I just described above. The launch application method takes in three parameters: the application id, the publisher id and a array of parameters if the application requires it. <span style="text-decoration: underline;">NOTE</span>: Your AIR application MUST have <a title="BrowserInvocation Information from Adobe" href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118676a5d46-8000.html#WS5b3ccc516d4fbf351e63e3d118666ade46-7e19">allowBrowserInvocation</a> set to true in it&#8217;s AIR application descriptor xml file for the badge to be able to launch your AIR application.</p>
<h5>Finding your application id</h5>
<p>Simply go to your AIR application&#8217;s folder and open the descriptor xml file. Look for the id node and that&#8217;s the id you want to use.</p>
<h5>Finding your publisher id</h5>
<p>This one was a bit trickier. First you need to install your AIR application on your system. Once installed, go to the folder where your application was installed and inside there will be a META-INF folder. Inside that folder there is a AIR folder with a publisherid file. Open that file and the string inside is your publisher id. For example: c:\program files\myairapp\META-INF\AIR\publisherid</p>
<p>That should do it. At this point you should have a basic working AIR badge. Now you can customize it any ways you like. Hope you all find this helpful! Feel free to leave any questions or comments.</p>
<h2>Resources:</h2>
<p><a title="Adobe Links" href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7e15.html">http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7e15.html</a></p>
<p><a title="Adobe Links" href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7ff1.html#WS5b3ccc516d4fbf351e63e3d118666ade46-7c9c">http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7ff1.html#WS5b3ccc516d4fbf351e63e3d118666ade46-7c9c</a></p>
<p><a title="Adobe Links" href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7ff0.html#WS5b3ccc516d4fbf351e63e3d118666ade46-7cca">http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7ff0.html#WS5b3ccc516d4fbf351e63e3d118666ade46-7cca</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeyrivera.com/2010/how-to-build-adobe-air-badge/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>What have I been up to recently&#8230;</title>
		<link>http://www.joeyrivera.com/2010/what-have-i-been-up-to-recently/</link>
		<comments>http://www.joeyrivera.com/2010/what-have-i-been-up-to-recently/#comments</comments>
		<pubDate>Thu, 10 Jun 2010 15:32:18 +0000</pubDate>
		<dc:creator>Joey</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://www.joeyrivera.com/?p=585</guid>
		<description><![CDATA[Last month was an action packed month for me. I had a few events going on and lots of work to get done. Atlanta PHP User Group We had a really cool presentation on load testing using JMeter and Xdebug by Brian DeShong. Load testing and profiling are very important to help identify possible bottlenecks [...]]]></description>
			<content:encoded><![CDATA[<p>Last month was an action packed month for me. I had a few events going on and lots of work to get done.</p>
<h2>Atlanta PHP User Group</h2>
<p>We had a really cool <a href="http://atlantaphp.org/archive/242">presentation</a> on load testing using <a href="http://jakarta.apache.org/jmeter/">JMeter</a> and <a href="http://xdebug.org/">Xdebug</a> by <a href="http://www.deshong.net/">Brian DeShong</a>. Load testing and profiling are very important to help identify possible bottlenecks in your application/server before reaching a breaking point. JMeter allows a user to setup different scenarios to run with varying loads (number of users, ramp up time). It&#8217;s pretty fancy with all the options you can do such as submit variables to pages to simulate login ins to an application and tracking sessions. Xdebug lets us analyze logs to see what was going on in your application to easily spot which part of the execution process took the most amount of time. At that point, you can look at your code to see how to improve that particular process.</p>
<p>At work we have an outside firm doing our testing/load testing so it was nice learning about JMeter so eventually we can start doing some of our own load tests for things we need done asap. I currently use Zend Studio&#8217;s profiler to profile my applications so I probably won&#8217;t be using Xdebug any time soon.</p>
<h2>TEK-X</h2>
<p><img class="alignleft" title="TEK-X Conference" src="http://tek.phparch.com/wp-content/themes/tekx/images/header-logo.png" alt="" width="300" height="100" />I asked around our local user group what conference they would recommend if they could only attend one PHP conference and this was the one I heard the most good things about. This was my first time attending a PHP conference and it was WELL worth it. The sessions were great with three tracks daily to choose from. The conference was small enough where you could spend time with the presenters interacting and asking questions. I met a bunch of new people which made the whole experience that much better. There was always something to do during presentations as well as after hours.</p>
<p>This is the web site for <a href="http://tek.phparch.com/">TEX-K</a> if you want more info or want to take a look at the <a href="http://tek.phparch.com/schedule/">schedule</a>. Some of my favorite were the two Flex sessions by <a href="http://caseysoftware.com/blog">Keith Casey</a> since I want to start doing more Flex and the Lost Art of Simplicty by <a href="http://www.joshholmes.com/blog/">Josh Holmes</a> was interesting as well. It was really nice having a bunch of Adobe and Microsoft people there. They were all great and helpful. We had been having some server hiccups at work and the guys at Microsoft were extremely helpful in trying to help us figure things out. We also learned from various people (both the MS and PHP crowd) that we (at work) should start using IIS instead of Apache for Windows. Microsoft has been spending resources in working with the PHP team to make sure things run smoother with PHP on IIS for Windows than before.</p>
<p>Two thumbs up for Microsoft and Adobe for being there and supporting the community (and for the drinks and dinners :p) . I&#8217;ll definitely try to go next year again.</p>
<h2>Flash Builder for PHP</h2>
<p><img class="alignleft" title="Flash Builder" src="http://www.adobe.com/products/flex/images/overview_flashbuildermnemonic.jpg" alt="" width="80" height="80" />I took a one day-8 hour course on using Flash Builder and wow&#8230; I&#8217;m sold. After working on Flash for so many years, Flex is just too amazing to ignore. The class was taught by Adobe certified <a href="http://stallons.com/bio.html">Jeanette Stallons</a> and it was a small class which was great for us since we could get a lot more time for questions and one on one time. She did a great job keeping our attention and was very easy to follow. This was a hands on class so we each had our own computer to work the examples with.</p>
<p>The class started with us learning about the different Adobe applications, the difference between Flash/Flex, and reasoning behind changing the name Flex builder to Flash builder. Then we went through the basics of the IDE and how to setup a project and what the different folders and files are for. Next is when things got fun. We started creating an application that communicates with the database through PHP. We did all the code manually to better appreciate the last lesson which was creating the exact same application in an automated fashion with literally only a few lines of code at most. That was the coolest part of this class, how easy it is to use the wizards (that actually spit out good code!) to be able to just click and drag and have everything working correctly in such a <span style="text-decoration: underline;">short amount of time</span>.</p>
<p>I already <a href="http://www.adobe.com/products/flashbuilder/">downloaded</a> the two month trial from the Adobe&#8217;s site and have been playing around with Flash Builder at work and at home.</p>
<h2>Google AdWords API v13 to v2009</h2>
<p>A few years ago I wrote an application that heavily uses the Google Adwords API. It worked without me touching it for years until recently Google <a href="http://code.google.com/apis/adwords/articles/migrating.html">changed</a> their Adwords API and my app completely stopped working. This was my fault of course since many months ago Google emailed me letting me know this was going to happen but at the time I figured there wouldn&#8217;t be much difference between both versions so I didn&#8217;t pay much attention to it&#8230; boy was I wrong.</p>
<p>The new API v2009 is very different since you call things differently now and many of the old services I was using no longer exist in the new version. I spent some time trying to rework my code to use the new calls but that was not working well for me. It just seemed as if I was wasting time instead of just starting over with a clean rewrite. Fortunately for me, after doing some research, I found that Google had already created a <a href="http://code.google.com/apis/adwords/v2009/docs/clientlibraries.html">client library</a> for PHP that already did all the heavy lifting code to interact with the services. I downloaded the library, ran a couple tests and everything was working perfectly. All I had to do was rewrite the application using the client library and everything is running smoothly again.</p>
<p>Thanks Google! You saved me a lot of time but don&#8217;t change your API again <img src='http://www.joeyrivera.com/blog_new/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> </p>
<h2>My Birthday</h2>
<p><img class="alignleft" title="Garmin 405 Watch" src="https://static.garmincdn.com/en/products/010-00658-10/g/cf-lg.jpg" alt="" width="300" height="300" />Not much to mention here other than it was my birthday last month as well so had dinners with parents and drinks with friends. I have been running a lot lately so I bought myself a nice new watch with my birthday money: <a href="https://buy.garmin.com/shop/shop.do?pID=11039">Garmin 405</a>. I saw this watch on sale on <a href="http://www.slickdeals.net/">slickdeals.net</a> for under $200 and I couldn&#8217;t resist. I&#8217;ve used it a couple times already and it&#8217;s great. The GPS seems to be working flawlessly for me so far and all the features it brings are neat to play with. My biggest sellers were: GPS to track my distance and pace and the heart rate monitor.</p>
<p><a href="http://www.atlantatrackclub.org/peachtree.htm">Peachtree Road Race</a>, here I come!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeyrivera.com/2010/what-have-i-been-up-to-recently/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Two thumbs up for the wifey!</title>
		<link>http://www.joeyrivera.com/2010/two-thumbs-up-for-the-wifey/</link>
		<comments>http://www.joeyrivera.com/2010/two-thumbs-up-for-the-wifey/#comments</comments>
		<pubDate>Mon, 22 Mar 2010 19:11:04 +0000</pubDate>
		<dc:creator>Joey</dc:creator>
				<category><![CDATA[Other]]></category>
		<category><![CDATA[ashley fleishel]]></category>
		<category><![CDATA[ashley rivera]]></category>
		<category><![CDATA[kroger]]></category>

		<guid isPermaLink="false">http://www.joeyrivera.com/?p=579</guid>
		<description><![CDATA[So my wife submitted a design for an eco-friendly bag contest for Kroger late last year. There were over 46,000 entries nation wide and she ended up winning second place!!! Great job sweets! Starting next month (April), if you shop at Kroger, you may be able to purchase her bag from your local Kroger store. [...]]]></description>
			<content:encoded><![CDATA[<p>So my wife submitted a design for an <a href="http://www.designareusablebag.com/vote-for-designs/top-10.aspx">eco-friendly bag contest for Kroger</a> late last year. There were over 46,000 entries nation wide and she ended up winning second place!!! Great job sweets!</p>
<p style="text-align: center;">
<p>Starting next month (April), if you shop at Kroger, you may be able to purchase her bag from your local Kroger store. Here is an article that just came out today from a local magazine:</p>
<p><a href="http://www.mdjonline.com/view/full_story/6794712/article-Marietta-graphic-designer-takes-2nd-in-Kroger-s-reusable-bag-competition?instance=home_news_1st_right">http://www.mdjonline.com/view/full_story/6794712/article-Marietta-graphic-designer-takes-2nd-in-Kroger-s-reusable-bag-competition?instance=home_news_1st_right</a></p>
<p>Feel free to visit Ashley&#8217;s blog and let her know she did a great job: <a href="http://ashleycf.wordpress.com/">Ashley&#8217;s Blog</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeyrivera.com/2010/two-thumbs-up-for-the-wifey/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
