<?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/"
	>

<channel>
	<title>PapayaSoft</title>
	<atom:link href="http://www.papayasoft.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.papayasoft.com</link>
	<description>Phuket web development</description>
	<pubDate>Tue, 17 Aug 2010 12:27:50 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Gotcha - SQL count() query with LIMIT clause</title>
		<link>http://www.papayasoft.com/2010/08/17/gotcha-sql-count-query-limit/</link>
		<comments>http://www.papayasoft.com/2010/08/17/gotcha-sql-count-query-limit/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 12:26:51 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
		<category><![CDATA[MySQL]]></category>

		<category><![CDATA[gotcha]]></category>

		<category><![CDATA[limit]]></category>

		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://www.papayasoft.com/?p=309</guid>
		<description><![CDATA[Bumped into an interesting feature today. Well, whether it&#8217;s a feature or a gotcha appears to be in the eye of the beholder. And, I&#8217;ll tell ya, for this particular beholder, it was a gotcha.
I&#8217;ve got some code that builds a SQL query from a variable set of parameters. Most parameters are involved with building [...]]]></description>
			<content:encoded><![CDATA[<p>Bumped into an interesting feature today. Well, whether it&#8217;s a feature or a gotcha appears to be in the eye of the beholder. And, I&#8217;ll tell ya, for this particular beholder, it was a gotcha.</p>
<p>I&#8217;ve got some code that builds a SQL query from a variable set of parameters. Most parameters are involved with building a dynamic WHERE clause. Other parameters are for pagination, setting a LIMIT clause on the query that eventually gets built. Another parameter is whether to make the query a COUNT() query or whether to actually pull rows from the db. </p>
<p>In the case where I build a COUNT() query, I was carelessly allowing a zero-based LIMIT clause - something like LIMIT 0,10 - to be appended to the query. No sweat, I  figured, since I really only need the single-row containing the count I am requesting.</p>
<p>However, it turns out that this LIMIT was actually be applied *before* the COUNT()-ing, not after. So, my COUNT() was completely wrong, often returning 0.</p>
<p>There&#8217;s an hour of my life - spent in furious frustration - that I&#8217;ll never get back.</p>
<p>Onward!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.papayasoft.com/2010/08/17/gotcha-sql-count-query-limit/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Martin Gardner and me</title>
		<link>http://www.papayasoft.com/2010/05/28/martin-gardner/</link>
		<comments>http://www.papayasoft.com/2010/05/28/martin-gardner/#comments</comments>
		<pubDate>Fri, 28 May 2010 13:42:03 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
		<category><![CDATA[mathematics]]></category>

		<category><![CDATA[infinity]]></category>

		<category><![CDATA[philosophy]]></category>

		<guid isPermaLink="false">http://www.papayasoft.com/?p=287</guid>
		<description><![CDATA[I just read on AskWoody.com that Martin Gardner, the longtime author of the Scientific American column &#8220;Mathematical Games&#8221;, has died at the age of 95.
I am a bit surprised at how it is affecting me.
As a kid, I loved his column. I took pride in solving the puzzles. The activity taught me focus and concentration. [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.papayasoft.com/wp-content/uploads/2010/05/martin_gardnerjpeg-300x209.jpg" alt="martin_gardnerjpeg" title="martin_gardnerjpeg" width="300" height="209" class="alignleft size-medium wp-image-303" /></p>
<p>I just read on <a href="http://www.askwoody.com/2010/martin-gardner-rip/">AskWoody.com</a> that Martin Gardner, the longtime author of the <em>Scientific American</em> column &#8220;Mathematical Games&#8221;, has died at the age of 95.</p>
<p>I am a bit surprised at how it is affecting me.</p>
<p>As a kid, I loved his column. I took pride in solving the puzzles. The activity taught me focus and concentration. It taught me problem solving. It taught me to think.</p>
<p>But most of all, it gave me my first exposure to the notions of logical incompleteness and unequal infinities. </p>
<p>With the naivety of youth, I believed that the universe was black and white. Statements were either true or false, and essentially all knowledge (using a sufficiently large book) could be expressed in language. </p>
<p>Further, infinity was infinity. the biggest thing there is. Nothing bigger than that, despite the common schoolyard escalation of taunts:</p>
<blockquote>
<p>&#8220;You have cooties.&#8221;</p>
<p>&#8220;Well, you have cooties plus one.&#8221;</p>
<p>&#8220;You have cooties plus two.&#8221;</p>
<p>&#8220;Oh, yeah? You have cooties times one hundred&#8221;, cleverly upping the stakes by switching from simple addition to the more powerful multiplication.</p>
<p>&#8220;Well, you have cooties times infinity!&#8221;</p>
<p>&#8220;Oh yeah? You have cooties times infinity-plus-one.&#8221;</p>
</blockquote>
<p>&#8230; and so on.</p>
<p>Still, infinity came to connote - at least to me - a sense of maximality, the sum totality of everything, of the universe. Of The Universe.</p>
<p>Martin Gardner&#8217;s column exposed me to <a href="http://en.wikipedia.org/wiki/G%C3%B6del%27s_incompleteness_theorem">Gödel&#8217;s Incompleteness Theorem</a> and <a href="http://www.absoluteastronomy.com/topics/Cantor%27s_theorem">Cantor&#8217;s Theorem</a> about cardinalities.</p>
<p>Gödel&#8217;s Incompleteness Theorem states that no consistent system of axioms whose theorems can be listed by an &#8220;effective procedure&#8221; (essentially, a computer program) is capable of proving all facts about the natural numbers. For any such system, there will always be statements about the natural numbers that are true, but that are unprovable within the system.</p>
<p>This has profound implications for reductionist attempts - to which I was inherently attracted in my youth - to reduce all knowledge to a set of indisputable, logically consistent axioms and deduction mechanisms. Essentially, if you depend upon axiomatic logic and consistency, you are limited in what you can prove. There exist statements that are expressible within the given system, but whose truth or falsity are not provable using only the tools of the system.</p>
<p>This result undermines language as the sole medium of defining knowledge, since language will always produce statements that are outside the reach of provable truth or falsity. It casts doubt on the binary notion of truth, opening up the mathematical discipline of fuzzy logic.</p>
<p>It even strikes closer to home for me, contradicting something my father explicitly told me when I was a child, one of his core beliefs: &#8220;If you can&#8217;t describe what you know, then you do not know it.&#8221;</p>
<p><img src="http://www.papayasoft.com/wp-content/uploads/2010/05/429px-diagonal_argument_2svg-300x297.png" alt="429px-diagonal_argument_2svg" title="429px-diagonal_argument_2svg" width="300" height="297" class="alignright size-medium wp-image-292" /></p>
<p>Gödel&#8217;s method of proof was his famous Diagonal Lemma, in which he starts with the logical system, its symbols and its constructs, and then proceeds to build an example of his elusive unprovable statement.</p>
<p>Using a similar diagonalization technique, Georg Cantor was able to demonstrate that the infinity that represents the natural numbers (1, 2, 3, 4&#8230;) was a &#8220;lesser&#8221; infinity than the infinity representing the real numbers (the numbers that represent measurable distances on a line), the former being a &#8220;countable&#8221; infinity and the latter an &#8220;uncountable&#8221; one. Further, he proved that there are ever-higher, unlimited levels of &#8220;greater&#8221; infinities, all of which are &#8220;uncountable&#8221;.</p>
<p>All this just blew me away. It fired my imagination. It opened my mind to an extraordinary universe, to universes, to multiverses. It inspired me to embrace the beauty of abstraction. It led me to study mathematics, first as an undergraduate, then as a graduate student, through to my doctorate degree.</p>
<p>Abstraction, modeling, language, truth, philosophy, knowledge, infinities, alternate possibilities, universes.</p>
<p>For me, it all started with Martin Gardner. My life would not be the same without the contribution that he made to it. I&#8217;m saddened at the news of his passing, but grateful for the door he opened for me.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.papayasoft.com/2010/05/28/martin-gardner/feed/</wfw:commentRss>
		</item>
		<item>
		<title>What to do about ZodiacFacts and #zf on Twitter?</title>
		<link>http://www.papayasoft.com/2010/05/09/zodiacfacts-zf-twitter-bot/</link>
		<comments>http://www.papayasoft.com/2010/05/09/zodiacfacts-zf-twitter-bot/#comments</comments>
		<pubDate>Sun, 09 May 2010 09:09:43 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Twitter]]></category>

		<category><![CDATA[Zend Framework]]></category>

		<category><![CDATA[bot]]></category>

		<category><![CDATA[zend]]></category>

		<guid isPermaLink="false">http://www.papayasoft.com/?p=273</guid>
		<description><![CDATA[The Twitter hashtag #zf has been used by the Zend Framework for several years now. The Twitter user @ZodiacFacts began using it some time ago, polluting the #zf stream with all that medieval nonsense. Zend Framework Project Lead Matthew Weier O&#8217;Phinney tweeted a reply to @ZodiacFacts politely requesting that he/she refrain from using the hashtag [...]]]></description>
			<content:encoded><![CDATA[<p>The Twitter hashtag <a href="http://twitter.com/#search?q=%23zf">#zf</a> has been used by the Zend Framework for several years now. The Twitter user <a href="http://twitter.com/ZodiacFacts/">@ZodiacFacts</a> began using it some time ago, polluting the #zf stream with all that medieval nonsense. Zend Framework Project Lead <a href="http://twitter.com/weierophinney">Matthew Weier O&#8217;Phinney</a> tweeted a reply to @ZodiacFacts politely requesting that he/she refrain from using the hashtag and @ZodiacFacts seems to have politely complied.</p>
<h3>So, what&#8217;s the problem?</h3>
<p>As of this writing, @ZodiacFacts has over 170,000 followers - a lamentable indictment on the state of human rationality. It is no surprise that some of them continue to retweet into the #zf stream.</p>
<p>There are not many of them, only a few each day. So, it&#8217;s only a minor annoyance. Still, life is filled with enough of minor annoyances that it&#8217;s desirable to remove/minimize them when we can.</p>
<h3>The solution, perhaps</h3>
<p>A Twitter Bot could be built that polls Twitter for tweets containing both @ZodiacFacts and #zf and then sends a politely worded reply to the Twitter user requesting that he refrain from using the #zf hashtag.</p>
<p>I have actually built a class on which such a bot can be based. And I have registered the Twitter account <a href="http://twitter.com/zfisforzend">@zfisforzend</a> to function as the sender. </p>
<p>But since the #zf hashtag should rightly be regarded as a community resource, I don&#8217;t really feel that it is my place to deploy the solution on my own. The &#8220;community&#8221; or even Zend HQ should make the decision about whether to deploy, the phrasing of the message, etc. After all, both of these things affect the public face of the project. Hey, it might even inflame the legions of @ZodiacFact fans to spam the #zf stream, just out of pique.</p>
<p>So, I am posting my current code so that if one of the project leaders wishes to use it - or to develop their own, which would no doubt be better than mine - then they can do so with little effort. I&#8217;d be happy to pass off the ownership of the @zfisforzend Twitter account to whatever community member wants to use it for this purpose.</p>
<pre class="brush: php">

/**
 * Access Twitter API, do twitter search, then reply
 *
 * @author David Weinraub ( david@papayasoft.com )
 */
class PS_TwitterSearchAndReplyBot
{
    /**
     * @var Zend_Service_Twitter
     */
    protected $_twitter = null;

    /**
     * @var string
     */
    protected $_reply = null;

    /**
     * Path to the file containing the id of the tweet to which we have replied
     *
     * @var string
     */
    protected $_sincePath = null;

    /**
     * @var string
     */
    protected $_userAgent = 'PapayaSoft-SearchAndReplyBot/1.0';

    /**
     * Constructor
     *
     * @param string $username Twitter username for the acct sending replies
     * @param string $password Twitter password for the acct sending replies
     * @param string $query the query we use to find tweets.
     * @param string $reply the text of the reply we wish to send
     * @param string $sincePath path to the file where we save the last replied tweet
     */
    public function __construct($username, $password, $query, $reply, $sincePath)
    {
        if ('' == $username){
            throw new Exception('User is required');
        }

        if ('' == $password){
            throw new Exception('Password is required');
        }

        $this->_twitter = new Zend_Service_Twitter($username, $password);
        $this->_twitter->getHttpClient()->setHeaders('useragent', $this->_userAgent);

        if ('' == $query){
            throw new Exception('Query is required');
        }
        $this->_query = $query;

        if ('' == $reply){
            throw new Exception('Reply is required');
        }
        $this->_reply = $reply;

        $this->_sincePath = $sincePath;
    }

    /**
     * Get the matching tweets
     *
     * @return array the matching tweets
     */
    public function getTweets()
    {
        $service = new Zend_Service_Twitter_Search();
        $service->getHttpClient()->setHeaders('useragent', $this->_userAgent);
        if (null == $sinceId){
            $sinceId = (int) $this->readSince();
        }
        $params = array(
            'since_id' => $sinceId,
        );
        return $service->search($this->_query, $params);
    }

    /**
     * Send the reply to a matching tweet
     *
     * @param array $tweet
     * @return void
     */
    public function sendReply($tweet)
    {
        $target = $tweet['from_user'];
        $reply = '@' . $target . ' ' . $this->_reply;

        $result = $this->_twitter->statusUpdate($reply, $tweet['id']);

        if ($result->isSuccess()){
            $this->writeSince($tweet['id']);
            return true;
        } else {
            throw new Exception('Failure posting status reply to target');
        }
    }

    /**
     * Save the id of the last tweet to which we have replied
     *
     * @param int $sinceId
     * @return <type>
     */
    public function writeSince($sinceId)
    {
        @$fp = fopen($this->_sincePath, 'w');

        if (!$fp){
            throw new Exception('Unable to open since-file for writing');
        }
        fwrite($fp, $sinceId);
        fclose($fp);
        return $this;
    }

    /**
     * Get the twitter id of the last tweet to which we have replied
     *
     * @return int
     */
    public function readSince()
    {
        return file_get_contents($this->_sincePath);
    }

    /**
     * Entry point. Do it all.
     */
    protected function run()
    {
        $tweets = $this->getTweets();
        foreach ($tweets as $tweet){
            $this->sendReply($tweet['from_user'], $tweet['id']);
        }
    }
}
</pre>
<p>Usage would be something along the following:</p>
<pre class="brush: php">

$bot = new PS_TwitterSearchAndReplyBot(
    'zfisforzend',
    'thepassword',
    '#zf AND @ZodiacFacts',
    'The ZF hashtag has been used by http://bit.ly/dlRih0 for 2+ years. Please do not use it for ZodiacFacts. Thanks! ;-)',
    dirname(__FILE__) .'/data/since.dat'
);
$bot->run();
</pre>
<p>Then set up a cron job to run this script with some polling frequency.</p>
<p>Note that the message we send should not contain either of the terms &#8220;#zf&#8221; or &#8220;Zend&#8221; directly. After all, those are search terms we all use in our Twitter clients. The last thing we want is for all these bot-generated replies to further pollute the targeted hashtag stream.</p>
<p>As you can see, it is general enough to serve as the base for other Twitter Reply bots. I confess that the code is only partially tested, but I think it conveys the idea. </p>
<p>So, whaddya think?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.papayasoft.com/2010/05/09/zodiacfacts-zf-twitter-bot/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Zend Framework on shared hosting</title>
		<link>http://www.papayasoft.com/2010/05/08/zend-framework-shared-hosting/</link>
		<comments>http://www.papayasoft.com/2010/05/08/zend-framework-shared-hosting/#comments</comments>
		<pubDate>Sat, 08 May 2010 15:54:33 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
		<category><![CDATA[Business]]></category>

		<category><![CDATA[Meta]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Zend Framework]]></category>

		<category><![CDATA[zend]]></category>

		<guid isPermaLink="false">http://www.papayasoft.com/?p=193</guid>
		<description><![CDATA[Zend Framework recommends - but does not rigidly enforce - a file structure for your application. Most of the prominent &#8220;getting started&#8221; sample apps - like the Zend Framework Quickstart, Rob Allen&#8217;s Getting Started tutorial, HariKT&#8217;s Base Files skeleton - use it:

Using this structure usually requires creating a virtual host pointing to this public folder [...]]]></description>
			<content:encoded><![CDATA[<p>Zend Framework recommends - but does not rigidly enforce - a file structure for your application. Most of the prominent &#8220;getting started&#8221; sample apps - like the <a href="http://framework.zend.com/manual/en/learning.quickstart.intro.html">Zend Framework Quickstart</a>, <a href="http://akrabat.com/zend-framework-tutorial-18/">Rob Allen&#8217;s Getting Started tutorial</a>, <a href="http://github.com/harikt/zfbase">HariKT&#8217;s Base Files skeleton</a> - use it:</p>
<p><img src="http://www.papayasoft.com/wp-content/uploads/2010/05/akrabat.png" alt="ZF recommended structure" title="ZF recommended structure" width="225" height="319" class="alignleft size-full wp-image-246" /></p>
<p>Using this structure usually requires creating a virtual host pointing to this <code>public</code> folder and then creating the file <code>public/.htaccess</code> that maps all non-file, non-directory requests to the index.php file. You then get to enjoy all the rich, creamy Zend goodness.</p>
<p>But sometimes you are stuck with shared hosting and you can&#8217;t always place your other app folders as siblings to your public web root. For example, one prominent web hosting company provides me a web root of the form <code>/usr/www/users/myusername</code> with a home directory of <code>/usr/home/myusername</code>. </p>
<p>So whaddya gonna do?</p>
<div style="clear:both; margin-bottom:20px;"> </div>
<h3>A Solution - Push Down and Protect</h3>
<p>This question has been <a href="http://stackoverflow.com/questions/1115547/zend-framework-on-shared-hosting">asked</a> and <a href="http://www.alberton.info/zend_framework_mod_rewrite_shared_hosting.html">answered</a> <a href="http://akrabat.com/zend-framework/zend-framework-on-a-shared-host/">many</a> <a href="http://www.ttech.it/en/article/2010/03/zend-framework-all-projects-files-on-document-root/">times</a>, but most of the solutions use either custom plugins or tricky .htaccess rules. There&#8217;s nothing wrong with those - and in general, they are proposed by people way smarter than me. So there is an argument for going with the best. As they used to say: &#8220;No one ever got fired for buying IBM.&#8221;</p>
<p>But there is a simpler way that has worked well for me: depart slightly from the recommended file structure and modify some include paths. I have seen this approach referenced before, in particular by <a href="http://stackoverflow.com/questions/1115547/zend-framework-on-shared-hosting/1115685#1115685">tharkun on Stackoverflow</a>, but I had not seen it written out explicitly. So, I offer it here in the hope that other ZF n00bs like me can benefit from it.</p>
<p>Essentially, I just push all my app folders down into a subfolder of the web root called something like <code>_zf</code>, web protect that <code>_zf</code> folder with a <code>Deny from All</code> in an <code>.htaccess</code> file for the folder, and change a few paths in the <code>index.php</code> entry point.</p>
<p>I presume that the shared hosting offers me a web root folder called <code>public_html</code>.</p>
<p>So, my folder structure looks like this:</p>
<p><img src="http://www.papayasoft.com/wp-content/uploads/2010/05/zfshared.png" alt="ZF application structure for shared hosting" title="ZF application structure for shared hosting" width="225" height="498" class="alignleft size-full wp-image-252" /></p>
<div style="clear:both;"> </div>
<p>I make sure that the file <code>public_html/_zf/.htaccess</code> prevents any direct web access:</p>
<pre class="brush: php">
Deny from All
</pre>
<p>This keeps anyone from viewing any of the non-public app files.</p>
<p>Then we just modify paths in <code>public_html/index.php</code> to point to the <code>_zf</code> folder, as follows:</p>
<pre class="brush: php">

set_include_path(implode(PATH_SEPARATOR,
    array(
        dirname(__FILE__)  . DIRECTORY_SEPARATOR . '_zf' . DIRECTORY_SEPARATOR . 'library',
        get_include_path(),
    )
));

// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/_zf/application'));

// Everything else is the same as usual. For example, using Zend_Application...

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

require_once 'Zend/Application.php';  

$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap()->run();
</pre>
<p>And that&#8217;s it!</p>
<p>A purely modular app structure can also be handled in this way. For example, you can simply put your <code>modules</code> folder inside your <code>application</code> folder. Since all the logic associated to module routing, module bootstrapping, and module-specific paths already resides within the framework, the setup above still works.</p>
<h3>The Downside</h3>
<p>There is an insidious down-side to all this. Best practice dictates keeping all those app folders - and especially the config files, rich with passwords and the like - out of the web root. In theory, we have that all handled with the <code>.htaccess Deny</code> on the <code>_zf</code>  folder. But it&#8217;s a single point of failure. If it fails for some reason - say, the .htaccess file doesn&#8217;t get deployed - then we are fully exposed to a wide variety of potential mischief.</p>
<p>There is some additional obscurity you can obtain by changing the name of the <code>_zf</code> folder to something (practically) unguessable. I could even imagine a cron job that renames the folder and makes corresponding changes to the <code>index.php</code> file. But that&#8217;s probably excessive. And, in any case, as we should all well know, relying solely on <a href="http://en.wikipedia.org/wiki/Security_through_obscurity">security through obscurity</a> is a poor approach.</p>
<p>But maybe this approach is useful to get an app off the ground with a customer who is stuck with his shared hosting package. At some point in the future, when the app is sufficiently profitable, maybe you can convince the customer to move to virtual private server hosting, at which point it&#8217;s a small modification to return to the standard ZF-recommend file structure.</p>
<p>Whaddya think?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.papayasoft.com/2010/05/08/zend-framework-shared-hosting/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Debugging PHP - Netbeans Code Templates for Zend_Debug and FirePHP</title>
		<link>http://www.papayasoft.com/2010/04/29/netbeans-firephp-zend-debug/</link>
		<comments>http://www.papayasoft.com/2010/04/29/netbeans-firephp-zend-debug/#comments</comments>
		<pubDate>Thu, 29 Apr 2010 14:51:11 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
		<category><![CDATA[Netbeans]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Zend Framework]]></category>

		<category><![CDATA[debug]]></category>

		<category><![CDATA[ide]]></category>

		<category><![CDATA[zend]]></category>

		<category><![CDATA[zf]]></category>

		<guid isPermaLink="false">http://www.papayasoft.com/?p=215</guid>
		<description><![CDATA[I recently changed my day-to-day PHP IDE to Netbeans and it&#8217;s been a pleasure. [Don't ask me what I was using before, too embarrassed to say.]

In particular, one of Netbeans&#8217; nice features is Code Templates, little snippets of text that you can insert into your document simply by typing a short prefix and then hitting [...]]]></description>
			<content:encoded><![CDATA[<p>I recently changed my day-to-day PHP IDE to <a href="http://netbeans.org/features/php/index.html">Netbeans</a> and it&#8217;s been a pleasure. [Don't ask me what I was using before, too embarrassed to say.]</p>
<p><img src="http://www.papayasoft.com/wp-content/uploads/2010/04/idea-lightbulb-med.jpg" alt="idea light bulb" title="idea-lightbulb-med" width="175" height="258" class="alignleft" /></p>
<p>In particular, one of Netbeans&#8217; nice features is Code Templates, little snippets of text that you can insert into your document simply by typing a short prefix and then hitting the <code>Tab</code> key. They are actually smarter than just static snippets in that they can contain variables that are dynamically filled/changed as you edit. Hugely useful. I use them constantly for a variety of tasks, but my most common use of code templates is for debugging.</p>
<p>One useful debug tool is <a href="http://www.firephp.org/">FirePHP</a> in conjunction with <a href="http://getfirebug.com/">Firebug</a>, especially for applications using AJAX.</p>
<p>Several weeks ago, <a href="http://www.jeremykendall.net/">Jeremy Kendall</a> (<a href="http://twitter.com/JeremyKendall/">@JeremyKendall</a>) helpfully <a href="http://jaybill.com/2007/10/01/the-most-useful-function-you-will-ever-use-in-the-zend-framework/">pointed me</a> to <code>Zend_Debug::dump()</code> which behaves like an enhanced var_dump(). I was actually gratified to see that it resembles one of my own hacks that I have been using for years, though <code>Zend_Debug::dump()</code> is, not surprisingly, more polished. </p>
<p>Following on that, <a href="http://www.stahlstift.de/">Markus</a> (<a href="http://twitter.com/derstahlstift">@derstahlstift</a>) posted a <a href="http://pastebin.com/sZB6RDwm">Netbeans code template</a> that uses <code>Zend_Debug::dump()</code>.</p>
<p>I admit that they are both cool, but I prefer to identify precisely where I am doing the dump, using PHP&#8217;s <a href="http://php.net/manual/en/language.constants.predefined.php">magic constants</a> <code>__FILE__</code> and <code>__LINE__</code>. This allows me to easily chase down the dump statements and remove them once the debugging is finished. </p>
<p>So, here are my own versions, both in the form of Netbeans Code Templates.</p>
<p>For <code>FirePHP::send()</code>:</p>
<pre class="brush: php">
FB::send("${VAR default="variable"} = " . $$${VAR} . ":: ${func default="func"} :: " . __FILE__ . "(" . __LINE__ . ")");
${cursor}
</pre>
<p>For <code>Zend_Debug::dump()</code>:</p>
<pre class="brush: php">
Zend_Debug::dump($$${VARIABLE variableFromNextAssignmentName default="variable"}, "${VARIABLE variableFromNextAssignmentName}", true);
echo "

" . __FILE__ . "(" . __LINE__ . ") :: ${function default="function"} :: ${message default="message"}

";
${selection}${cursor}
</pre>
<p>Whaddya think? Do you have any tricks/shortcuts that you use for debugging? Let me know.</p>
<p>Cheers!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.papayasoft.com/2010/04/29/netbeans-firephp-zend-debug/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Zend Framework View Helper to Lowercase Titles</title>
		<link>http://www.papayasoft.com/2010/03/31/zend-framework-view-helper-lowercase-titles/</link>
		<comments>http://www.papayasoft.com/2010/03/31/zend-framework-view-helper-lowercase-titles/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 16:24:15 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Web]]></category>

		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://www.papayasoft.com/?p=210</guid>
		<description><![CDATA[When working on a web app, I often find myself with my local development version open in one browser window with the live version open in another. To allow me quickly distinguish one from the other, I like to tweak the rendering in the development version by converting the title to lower case.
Since I have [...]]]></description>
			<content:encoded><![CDATA[<p>When working on a web app, I often find myself with my local development version open in one browser window with the live version open in another. To allow me quickly distinguish one from the other, I like to tweak the rendering in the development version by converting the title to lower case.</p>
<p>Since I have recently begun using <a href="http://framework.zend.com/">Zend Framework</a> for much of my development, I wrote a little view helper to handle it.</p>
<pre class="brush: php">

class App_View_Helper_HeadTitle extends Zend_View_Helper_HeadTitle
{
    public function headTitle($title = null, $setType = Zend_View_Helper_Placeholder_Container_Abstract::APPEND)
    {
        if (null !== $title &#038;&#038; APPLICATION_ENV == 'development'){
            $title = strtolower($title);
        }
        return parent::headTitle($title, $setType);
    }
}
</pre>
<p>To use it, just add the helper path to your bootstrap. For example,you could do it in your <code>config/application.ini</code> with:</p>
<pre class="brush: php">
resources.view[] =
resources.view.helpers.App_View_Helper_ = "App/View/Helper"
</pre>
<p>The calls to <code>$this->headTitle()</code> in your view scripts or layout scripts remain unchanged.</p>
<p>As a side note, a great repository of Zend Framework snippets is at the aptly named site <a href="http://www.zfsnippets.com/">ZFSnippets.com</a>.</p>
<p>Do you use any similar tricks or snippets in your development? Let me know via the comments.</p>
<p>Cheers!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.papayasoft.com/2010/03/31/zend-framework-view-helper-lowercase-titles/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Upgrading MySQL - Error 1045 in Configure Instance Wizard</title>
		<link>http://www.papayasoft.com/2010/03/18/upgrade-mysql-error-1045-configure-instance-wizard/</link>
		<comments>http://www.papayasoft.com/2010/03/18/upgrade-mysql-error-1045-configure-instance-wizard/#comments</comments>
		<pubDate>Thu, 18 Mar 2010 16:30:18 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.papayasoft.com/?p=201</guid>
		<description><![CDATA[I recently upgraded my local database server from MySQL 4.1 to MySQL 5.1 on Windows XP. Got stuck in a jam involving root passwords and MySQL error 1045 that took hours to chase and fix. As a way for me to remember, and in the hope that it helps someone, else in a similar fix, [...]]]></description>
			<content:encoded><![CDATA[<p>I recently upgraded my local database server from MySQL 4.1 to MySQL 5.1 on Windows XP. Got stuck in a jam involving root passwords and MySQL error 1045 that took hours to chase and fix. As a way for me to remember, and in the hope that it helps someone, else in a similar fix, I want to detail what happened and the silver bullet that did the job.</p>
<p><span id="more-201"></span></p>
<p>[As a side note, I should have done the upgrade ages ago. But I had so many local databases on my server, and though an in-place upgrade - just copy the data directory of the old version to the new version - is possible <em>within</em> a series, it is not advisable when jumping to a <em>new</em> series. The alternative is to export/dump the databases and then re-import. I certainly could have used <code>phpMyAdmin</code>, but since I had so many local databases on my server, it would have been obnoxious to do it that way. I finally got around to hacking together a little backup script that queries the server for all its databases and calls <code>mysqldump</code> on each one. I also wrote an analogous restore script that was used to import the dumped databases into the new server.]</p>
<p>So, after backing up everything, and removing the 4.1 installation - including a manual deletion of all the orphan files that the uninstaller leaves behind, as well as a manual hunt-and-destroy of all MySQL references in the registry - I set about installing the 5.1 version. All smooth, right up until the last step: Configuring the server and installing the daemon as a service using the Instance Configuration Wizard. </p>
<p>The wizard asks a bunch of questions about maximum concurrent connections, transaction support, multi-language support, all straightforward. But at the end, it wants to create a new root passwords and before it lets you do that, it asks for the old ones. </p>
<p>The sticky part was that no matter what I did, I could not get the Wizard to accept my new root password. I find this pretty goofy, since this is supposed to be a brand new install. Even worse, I find it mysterious. How does it even know that there are old passwords out there? Didn't I delete everything? </p>
<p>But sometimes, you don;t have the luxury of contemplating the mysteries of the universe. Deadlines to meet. Mouths to feed. Plow ahead.</p>
<p>Apparently, I was not correctly reporting the old root password. I hardly ever use the root password, just generally safer to use a limited-privileges user account.</p>
<p>And no matter what I did - repeated uninstalls, manual deletes, restarts, etc - nothing could get past this critical step.</p>
<p>A bit of searching came up with a bunch of folks complaining in a <a href="http://bugs.mysql.com/bug.php?id=6891">MySQL bug report</a>of a similar issue, but none of the solutions there worked for me. The hero of the day was Jay Alverson, who <a href="http://forums.mysql.com/read.php?10,256285,256392#msg-256392">comments on a MySQL forum</a> that you need to delete the folder:</p>
<p><code>C:\Documents and Settings\All Users\MySQL</code></p>
<p>Turns out that all my old databases were there, including the <code>mysql</code> database that contains all the users, including the root user, and their passwords. Once that bad boy was gone, the wizard stopped asking me for the old root password, and simply allowed me to set the new one. Whew!</p>
<p>Hope it helps.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.papayasoft.com/2010/03/18/upgrade-mysql-error-1045-configure-instance-wizard/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Siam Villa Rentals - an information portal for Phuket villa rentals</title>
		<link>http://www.papayasoft.com/2010/03/10/siam-villa-rentals-an-information-portal-for-phuket-villa-rentals/</link>
		<comments>http://www.papayasoft.com/2010/03/10/siam-villa-rentals-an-information-portal-for-phuket-villa-rentals/#comments</comments>
		<pubDate>Wed, 10 Mar 2010 05:39:01 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
		<category><![CDATA[Business]]></category>

		<category><![CDATA[SEO]]></category>

		<category><![CDATA[phuket]]></category>

		<category><![CDATA[property]]></category>

		<category><![CDATA[rentals]]></category>

		<category><![CDATA[thailand]]></category>

		<guid isPermaLink="false">http://www.papayasoft.com/2010/03/10/siam-villa-rentals-an-information-portal-for-phuket-villa-rentals/</guid>
		<description><![CDATA[One of my customers will be soon be launching a new website providing information for visitors interested in Phuket and in Phuket villa rentals. 
Siam Real Estate, a Phuket-based real-estate agent specializing in Phuket property will soon launch Siam Villa Rentals.
At present, only a placeholder page. But stay tuned.
]]></description>
			<content:encoded><![CDATA[<p>One of my customers will be soon be launching a new website providing information for visitors interested in Phuket and in <a href="http://www.siamvillarentals.com/">Phuket villa rentals</a>. </p>
<p>Siam Real Estate, a Phuket-based real-estate agent specializing in <a href="http://www.siamrealestate.com/">Phuket property</a> will soon launch <a href="http://www.siamvillarentals.com/">Siam Villa Rentals</a>.</p>
<p>At present, only a placeholder page. But stay tuned.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.papayasoft.com/2010/03/10/siam-villa-rentals-an-information-portal-for-phuket-villa-rentals/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Separating Pingbacks and Trackbacks from Comments in Wordpress</title>
		<link>http://www.papayasoft.com/2010/02/21/wordpress-pingbacks-trackbacks/</link>
		<comments>http://www.papayasoft.com/2010/02/21/wordpress-pingbacks-trackbacks/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 04:44:33 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
		<category><![CDATA[Meta]]></category>

		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://www.papayasoft.com/?p=176</guid>
		<description><![CDATA[I quite like my current Wordpress theme: Fresh from Wolfgang Bartelme.
But now that I am getting some trackbacks and pingbacks, I notice that the comment handling is missing something that I generally value in a blog. When listing comments, I prefer the real, human comments to be separated from the pingbacks/trackbacks. Although the pingbacks/trackbacks are [...]]]></description>
			<content:encoded><![CDATA[<p>I quite like my current Wordpress theme: <a href="http://www.ilemoned.com/wordpress/wptheme-fresh/">Fresh</a> from <a href="http://www.bartelme.at/">Wolfgang Bartelme</a>.</p>
<p>But now that I am getting some <a href="http://en.wikipedia.org/wiki/Trackback">trackbacks</a> and <a href="http://en.wikipedia.org/wiki/Pingback">pingbacks</a>, I notice that the comment handling is missing something that I generally value in a blog. When listing comments, I prefer the real, human comments to be separated from the pingbacks/trackbacks. Although the pingbacks/trackbacks are completely important for their SEO value, I find that they can interrupt the flow of the conversation, disrupting the continuity. In my opinion, it&#8217;s better to list them separately.</p>
<p>Fortunately, it&#8217;s pretty easy to do. The theme file <code>comments.php</code> usually contains a loop that renders all the comments. The core of the technique is to use the Wordpress function <code>get_comment_type()</code> to determine the type of comment, then build two distinct buffers, one for which get_comment_type() returns &#8216;comment&#8217;, another for all the others (the trackbacks and pingbacks). </p>
<p>More details - though using a slightly different overall approach - can be found at <a href="http://www.ryanjparker.net/separating-pingbacks-and-trackbacks-from-comments-in-wordpress/">Ryan J. Parker&#8217;s blog</a> which, ironically, uses a modified version of the Fresh theme and where I suspect that this very post itself will appear as a pingback, nicely separated from the real human comments. <img src='http://www.papayasoft.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.papayasoft.com/2010/02/21/wordpress-pingbacks-trackbacks/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Conflict between Google Translate widget and Firefox Flashblock extension</title>
		<link>http://www.papayasoft.com/2010/01/26/google-translate-flashblock-firefox/</link>
		<comments>http://www.papayasoft.com/2010/01/26/google-translate-flashblock-firefox/#comments</comments>
		<pubDate>Tue, 26 Jan 2010 16:06:25 +0000</pubDate>
		<dc:creator>david</dc:creator>
		
		<category><![CDATA[HTML]]></category>

		<category><![CDATA[Javascript]]></category>

		<category><![CDATA[Web]]></category>

		<category><![CDATA[extension]]></category>

		<category><![CDATA[firefox]]></category>

		<category><![CDATA[flash]]></category>

		<category><![CDATA[google]]></category>

		<guid isPermaLink="false">http://www.papayasoft.com/?p=163</guid>
		<description><![CDATA[The Google Translate widget allows webmasters to add on-demand translation of a website page. Very easy to configure and deploy. 
The rendered widget appears in the browser as a simple select dropdown with options for all the language supported by Google Translate. When the user selects his desired target language, the widget is supposed to [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://translate.google.com/translate_tools?hl=en&#038;layout=1&#038;eotf=1&#038;sl=en&#038;tl=hu">Google Translate widget</a> allows webmasters to add on-demand translation of a website page. Very easy to configure and deploy. </p>
<p>The rendered widget appears in the browser as a simple select dropdown with options for all the language supported by Google Translate. When the user selects his desired target language, the widget is supposed to contact the Google Translate mother ship, translate the text on the page, and then add an fixed iframe panel at the top of the browser viewport, followed by the translation of the page. The translated page even implements onmouseover handlers for text-based elements that display the original source text. Sweet.</p>
<p>It has worked great for me in the past. But I recently did a new deployment and I was unable to get the widget to work. When I (as the user) selected my target language, I got the following:</p>
<blockquote><p>Error: The server could not complete your request. Try again later.</p></blockquote>
<p>A bit more poking showed that it was only happening in Firefox. All my other browsers were ok. Eventually, I narrowed it down to a conflict with the Flashblock extension. Disabling the extension solved the problem.</p>
<p>Now, the tough choice is to run without the Flashblock or without the Google Translate. But at least I can deploy for the customer.</p>
<p><strong>2010-02-20 Update:</strong> The mere presence of the enabled Flashblock extension when visiting a page with the translate widget does not cause the problem. The issue only occurs when the page has Flash content and the extension is configured to block Flash on that page. </p>
<p>The reason: The widget appears to actually use Flash!</p>
<p>In the file </p>
<p><code><a href="http://translate.googleapis.com/translate_static/js/element/main.js">http://translate.googleapis.com/translate_static/js/element/main.js</a></code></p>
<p>the function <code>wf()</code> seems to add Flash embed code into the page. I imagine that Flashblock is detecting this attempted insertion and is doing its magic.</p>
<p>I actually find it interesting - and impressive - that the Flashblock extension is smart enough to not only find/block Flash content on initial page load, but also at any time after that. I imagine it monitors the DOM and is vigilantly swaps out any Flash embeddings with its own replacement button.</p>
<p>I can see that the widget creates several iframes, at least one of which has Flash content pulled from the domain <code>translate.googleapis.com</code>. It stands to reason - well, at least to me - that enabling Flash content for this domain should do the trick. But so far, no luck. ;-(</p>
]]></content:encoded>
			<wfw:commentRss>http://www.papayasoft.com/2010/01/26/google-translate-flashblock-firefox/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
