<?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>amnuts &#187; PHP</title>
	<atom:link href="http://blog.amnuts.com/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.amnuts.com</link>
	<description>php projects, javascript, and... stuff.</description>
	<lastBuildDate>Fri, 27 Jan 2012 21:15:48 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>PHP Team Development book review</title>
		<link>http://blog.amnuts.com/2009/12/07/php-team-development-book-review/</link>
		<comments>http://blog.amnuts.com/2009/12/07/php-team-development-book-review/#comments</comments>
		<pubDate>Mon, 07 Dec 2009 11:48:32 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[packt]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[review]]></category>

		<guid isPermaLink="false">http://blog.amnuts.com/?p=139</guid>
		<description><![CDATA[So I&#8217;ve finally finished the book!  OK, I finished it a couple weeks ago but haven&#8217;t had a chance to post up a review yet.  Of course, I had every intention of finishing it a lot earlier considering I was flying for nine hours to the States and then another few hours on to Mexico [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.packtpub.com/php-team-development?utm_source=blog.amnuts.com&amp;utm_medium=link&amp;utm_content=blog&amp;utm_campaign=mdb_000684"><img style="float:right;border:0;margin:0 0 10px 10px;" src="https://www.packtpub.com/images/100x123/1847195067.png" alt="Book cover" /></a>So I&#8217;ve finally finished the book!  OK, I finished it a couple weeks ago but haven&#8217;t had a chance to post up a review yet.  Of course, I had every intention of finishing it a lot earlier considering I was flying for nine hours to the States and then another few hours on to Mexico &#8211; and the journey back again! &#8211; but that really was just wishful considering I was travelling with my two year old son.  Oh well! <img src='http://blog.amnuts.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>On with the book review&#8230;</p>
<p>The book, as the title makes it plainly obvious, is about <a href="http://www.packtpub.com/php-team-development?utm_source=blog.amnuts.com&amp;utm_medium=link&amp;utm_content=blog&amp;utm_campaign=mdb_000684">developing your team in relation to working with PHP</a>.  It&#8217;s aimed at, well, pretty much anyone who has an interest in developing or working in a team, be it managers who need to set up and manage teams or developers working within a team who want to improve their work flow and procedures, or anyone in between.  It does this by giving an overview on several subjects, but doesn&#8217;t go as far as to tell you that you must do x, y or z.  This is understandable, though, as every team is different and the book acknowledges this.</p>
<p><span id="more-139"></span>Chapter 1 discusses the need for teams and the use of established software engineering patterns that can help as well as touching on some tools such as issue tracking, source control, etc.  This chapter is good if you&#8217;re not sure with a lot of terminology as the overview covers a few key topics such as continuous integration and regression, and also touches on software development principles.  It doesn&#8217;t go in to depth about any one thing, as they&#8217;re covered in further chapters.</p>
<p>Chapter 2 covers MVC (Model View Controller) design principles and how you might form you team to deal with different aspects of the MVC pattern.  To be honest, if you&#8217;ve dealt with MVC at all in your job then this chapter holds no surprises, as you will know how the pattern works and how you would give responsibilities to different team groups/members.  However, if you&#8217;ve not had any experience at all then it offers a nice little introduction to the pattern.  (Remember, though, that this is not about how you would code the MVC pattern or use it in your project &#8211; it&#8217;s about making the principles of the pattern known to you and how it may fit in to team working.)</p>
<p>Chapter 3 is about dealing with complexity.  That is to say, if you have a complex project or application then this chapter gives you an idea on how to manage that and implement things that will make your job easier.  Essentially, what this chapter comes down to is why it&#8217;s a good idea to use a framework.  Again, it&#8217;s nothing new if you&#8217;ve already used frameworks (generally by then you know all the reasons why it tends to be a good thing for complex projects), but if you&#8217;re contemplating using one, or sit in a more managerial role and want to know why your developers are using one, then it&#8217;s worth the read.  At the end of the chapter the author also gives links to a number of different frameworks &#8211; some of which I hadn&#8217;t heard of before &#8211; along with their license type and a brief description.  What I especially liked about this chapter is that the author came over quite framework agnostic.  He wasn&#8217;t saying that one framework is better than another or which you should use &#8211; he supplies a list of frameworks and arms you with knowledge of what to look for in a framework (commercial license, documentation, support, code quality, security, etc.) and sets you on your way.  It is, of course, up to you to choose a framework that best suits your project and then integrate that in to your team workings.  This is a Good Thing!</p>
<p>Chapter 4 is about the process to get from the concept of an application to the end product and the steps in between.  There are a number of flow charts throughout this chapter that help you understand the process, and for someone like me who generally goes from being told someone wants an application,  to getting a brief functional requirements set and then making the thing, I can see that I have room for improvement! <img src='http://blog.amnuts.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Chapter 5 is about Agile development, and probably the chapter I was looking forward to the most.  Agile development was something I&#8217;d heard about, had an ever-so vague idea of what it was, but wasn&#8217;t too sure.  this chapter tells you what the principles are behind Agile development, how is works when dealing with the customer and a wide general overview.  The chapter then goes on to cover Extreme Programming (XP) a bit, and how Agile and XP can work in the team, pair programming, sustainable working styles for the developers, stand-up meetings, and so on.  It was good to find out a lot of how I work falls under Agile/XP, even though I didn&#8217;t know it at the time!  I learned a lot from this chapter and know a number of things I want to try to implement in to my working practice.</p>
<p>Chapter 6 is about collaboration among the team.  Basically it covers how source control is helpful, bug control and reporting, and ways developers can communicate (mailing lists, for example).  Useful stuff if you don&#8217;t know about it already, but pretty much any developer I know already uses source control in one form or another, as well as bug reporting, mailing lists, IRC, and everything else.</p>
<p>Chapter 7, the final chapter, is about continuous integration &#8211; what happens when your project needs to change, how does the project evolve, how to ensure team success and more.  Even though this is a distinct chapter in itself, I did get the feeling that it was more like a summary chapter of everything that you had just read.  But this was probably just because the author was referencing a number of his earlier chapters because they relatedto what he was taling about at the time.</p>
<p><strong>Conclusion</strong></p>
<p>This book is only 160 or so pages in size and it tries to cram a <em>lot</em> of information in to it.  There are times I wish the author could have gone in to more detail, but could also very much appreciate that the author didn&#8217;t have enough room to do so.  I actually quite liked that it was a really high-level overview for the most part, because it gave me a lot of ideas of things I want to investigate further and can now go and find resources that covers those bits in much more details.</p>
<p>Because I know quite a number of principles this book covered, such as the MVC chapters, source control, etc., I didn&#8217;t take quite so much away from it as another person may &#8211; and I&#8217;m sure other developers would feel the same &#8211; but I did still learn a lot from it, such as the agile development, and a number of keys principles that mayhelp me manage my time better as well as have a more integrated team.</p>
<p>However, this book wasn&#8217;t all roses and there were a number of things I really didn&#8217;t like.  The first thing is the authors style of writing.  I honestly didn&#8217;t gel with it very well and actually struggled to get past the first couple of chapters.  There was an overabundance of commas &#8211; sometimes breaking up the sentence in odd places &#8211; and it because a little repetitive and word for no reason.  My wife accuses me of using commas too much, which I probably do, but the amount in this book just caused me a headache!  The writing style I could get over (as mine&#8217;s not the best, but then, I&#8217;m not trying to sell you a book!), but the one thing that <em>really</em> pissed me off was that fact that the credits included a proof reader!!  WHAT?!  I lost count of the times &#8216;form&#8217; was used when it should have been &#8216;from&#8217;, or the spelling mistakes, grammatical errors, or missing words entirely!  A couple of my favourites is when the author was discussing the use of functional programming vs. OOP, and then goes on to say, &#8220;Be it fictional programming you are using or object-oriented programming&#8230;&#8221;  <em>Fictional</em> programming!  And this highlights the commas quite nicely, &#8220;&#8230;we might be about to deal with estimates that are off the mark for some time, in the long run, both, the development team as well as clients and users will become frustrated&#8230;&#8221;  I don&#8217;t so much blame the author for these mistakes &#8211; I can&#8217;t imagine the pressure of writing a book and trying to get it spot on &#8211; but isn&#8217;t that why you employ proof readers and editors??</p>
<p>All in all I&#8217;d say that if you&#8217;ve been developing for a while and had any team experience then this book wont be of much use to you.  However, if you&#8217;ve never worked in a team environment, or don&#8217;t have much development experience, are a manager or something like that, then you may find this book quite beneficial to you for an overview of working in and establishing team working principles.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.amnuts.com/2009/12/07/php-team-development-book-review/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Team Development (book)</title>
		<link>http://blog.amnuts.com/2009/09/30/php-team-development-book/</link>
		<comments>http://blog.amnuts.com/2009/09/30/php-team-development-book/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 09:13:57 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[packt]]></category>

		<guid isPermaLink="false">http://blog.amnuts.com/?p=136</guid>
		<description><![CDATA[The other day I had a new book sent to me called PHP Team Development, written by Samisa Abeysinghe and published by Packt Publishing. Unfortunately, it arrived at work when I was on holiday so I haven&#8217;t been able to have a look at it yet. :-/ However, I&#8217;m back today and have the book [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.packtpub.com/php-team-development?utm_source=blog.amnuts.com&amp;utm_medium=link&amp;utm_content=blog&amp;utm_campaign=mdb_000684"><img style="float:right;border:0;margin:0 0 10px 10px;" src="https://www.packtpub.com/images/100x123/1847195067.png" alt="Book cover" /></a>The other day I had a new book sent to me called <a href="http://www.packtpub.com/php-team-development?utm_source=blog.amnuts.com&amp;utm_medium=link&amp;utm_content=blog&amp;utm_campaign=mdb_000684">PHP Team Development</a>, written by Samisa Abeysinghe and published by Packt Publishing.  Unfortunately, it arrived at work when I was on holiday so I haven&#8217;t been able to have a look at it yet. :-/  However, I&#8217;m back today and have the book in my hands  (well, not literally, of course, else typing would be much more difficult), so am looking forward to diving in to it.</p>
<p>Hopefully have a bit of a review posted up here some time soon!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.amnuts.com/2009/09/30/php-team-development-book/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Shorten urls automatically with a Zend Framework filter</title>
		<link>http://blog.amnuts.com/2009/02/15/shorten-urls-automatically-with-a-zend-framework-filter/</link>
		<comments>http://blog.amnuts.com/2009/02/15/shorten-urls-automatically-with-a-zend-framework-filter/#comments</comments>
		<pubDate>Sun, 15 Feb 2009 01:24:10 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[filter]]></category>

		<guid isPermaLink="false">http://blog.amnuts.com/?p=123</guid>
		<description><![CDATA[I think we can all agree that URL shortening services are great and are very handy to tidy up those long and obnoxious links. However, a lot of the time people simply forget to use them, or often don&#8217;t know about them in the first place. I&#8217;ve noticed this in a blog system I wrote [...]]]></description>
			<content:encoded><![CDATA[<p>I think we can all agree that URL shortening services are great and are very handy to tidy up those long and obnoxious links.  However, a lot of the time people simply forget to use them, or often don&#8217;t know about them in the first place.  I&#8217;ve noticed this in a blog system I wrote using Zend Framework.  On one hand I love that people post messages, but on the other it annoys me that they may supply a link that is so long it breaks the formatting of the page, or looks just plain ugly.</p>
<p>So what are my options?  I could train everyone who posts blogs on the system to use a url shortening service or I could manually tweak all the links myself.  As solutions they are not very practical at all; I don&#8217;t have the time to change any/all links myself, and I certainly don&#8217;t have enough patience to train everyone!  So an automatic way of doing things is needed, and the filtering in Zend Framework comes to the rescue!</p>
<p><span id="more-123"></span><br />
Zend Framework has a lot of filters that you can use right out of the box.  They do all sorts such as string tags, newlines, camel case strings, and so on.  The framework also provides an interface so you can easily create your own filters.  For example, <a href="/2008/06/05/stringtotitle-filter/">converting a string to title case</a>.  With that in mind you could see how easy it&#8217;d be to create a filter to scan for urls and shorten them.  And that&#8217;s exactly what this filter does!  It will scan the supplied text for any http or https urls, and then, if they are past a certain size, it will attempt to connect to a url shortening service and then replace the long urls with the short.</p>
<pre lang="php">
/**
 * Shorten urls found in text.
 *
 * This filter will scan the supplied text for any http or https urls, and
 * then, if they are past a certain size, it will attempt to connect to a
 * url shortening service and then replace the long urls with the short.
 *
 * Two services endpoints are in the class - tinyurl and is.gd - but there's
 * nothing to stop you supplying a different end point, so long as the format
 * of the end point has one string directive (%s) and the service simply
 * returns a short url.
 *
 * @copyright Copyright (c) 2009, Andrew Collington
<php @amnuts.com>
 * @license New BSD License
 */
class Amnuts_Filter_ShortenUrls implements Zend_Filter_Interface
{
    const REGEX = "~(?:https?://(?:(?:(?:(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?:\d+)(?:\.(?:\d+)){3}))(?::(?:\d+))?)(?:/(?:(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[;:@&#038;=])*)(?:/(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[;:@&#038;=])*))*)(?:\?(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[;:@&#038;=])*))?)?)~";
    const SERVICE_ISGD    = 'http://is.gd/api.php?longurl=%s';
    const SERVICE_TINYURL = 'http://tinyurl.com/api-create.php?url=%s';

    /**
     * Options array containing:
     *
     *    - maxsize
     *      Maximum size the url can be before attempting to shorten it
     *    - service
     *      The url to the service API that returns a short url
     *    - timeout
     *      The maximum time allowed for a connection
     *
     * @var array
     */
    public $options = array(
        'maxsize' => 35,
        'service' => self::SERVICE_ISGD,
        'timeout' => 5
    );

    /**
     * Set options on construct
     *
     * @param array $options
     */
    public function __construct(array $options = array())
    {
        if (!empty($options)) {
            $this->options = array_merge($this->options, $options);
        }
    }

    /**
     * Filter the text.
     *
     * The filtering may take some time, depending on how many links are in
     * the text to be shortened, how responsive the service is, etc.
     *
     * @param string $text
     * @return string
     * @see Zend_Http_Client, Zend_Http_Response
     */
    public function filter($text)
    {
        $matches = $replacements = array();
        $matched = preg_match_all(self::REGEX, $text, $matches, PREG_PATTERN_ORDER);
        if ($matched) {
            $http = new Zend_Http_Client();
            foreach ($matches[0] as $url) {
                if (strlen($url) > $this->options['maxsize']) {
                    $http->setConfig(array(
                        'timeout' => $this->options['timeout']
                    ));
                    $http->setUri(
                        sprintf($this->options['service'], urlencode($url))
                    );
                    $response = $http->request(Zend_Http_Client::GET);
                    if ($response->isSuccessful()) {
                        $replacements[$url] = $response->getBody();
                    }
                    $http->resetParameters();
                }
            }
        }
        if (empty($replacements)) {
            return $text;
        }
        return str_replace(
            array_keys($replacements),
            array_values($replacements),
            $text
        );
    }
}
</php></pre>
<p>It&#8217;s very easy to use, too:</p>
<pre lang="php">
$shorten = new Amnuts_Filter_ShortenUrls();
$updated = $shorten->filter($text);
</pre>
<p>Here&#8217;s an example of using tinyURL as the service and only converting urls in the text that are longer than 50 characters:</p>
<pre lang="php">
$shorten = new Amnuts_Filter_ShortenUrls(array(
    'maxsize' => 50,
    'service' => Amnuts_Filter_ShortenUrls::SERVICE_TINYURL
));
$updated = $shorten->filter($text);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.amnuts.com/2009/02/15/shorten-urls-automatically-with-a-zend-framework-filter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quick and easy email encoding view helper</title>
		<link>http://blog.amnuts.com/2008/09/23/quick-and-easy-email-encoding-view-helper/</link>
		<comments>http://blog.amnuts.com/2008/09/23/quick-and-easy-email-encoding-view-helper/#comments</comments>
		<pubDate>Tue, 23 Sep 2008 11:17:27 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Code snippets]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[simple]]></category>
		<category><![CDATA[view helper]]></category>

		<guid isPermaLink="false">http://blog.amnuts.com/?p=73</guid>
		<description><![CDATA[Here&#8217;s a quick and easy view helper for Zend Framework that will encode an email address. It will encode just an email address or return a whole mailto link. The encoding is basically the same as in the Smarty template engine. Obviously there&#8217;s a lot of room for improvement; javascript encoding, representation as an image, [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a quick and easy view helper for Zend Framework that will encode an email address.  It will encode just an email address or return a whole mailto link.  The encoding is basically the same as in the Smarty template engine.</p>
<p>Obviously there&#8217;s a lot of room for improvement; javascript encoding, representation as an image, and so on&#8230; but then it wouldn&#8217;t be quick an easy &#8211; it&#8217;d be slightly longer and just a little more complex. <img src='http://blog.amnuts.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p><span id="more-73"></span></p>
<pre class="brush: php; title: ; notranslate">
class Amnuts_View_Helper_EncodeEmail extends Zend_View_Helper_Abstract
{
    /**
     * Return the class on direct calls.
     *
     * @return Amnuts_View_Helper_EncodeEmail
     */
    public function encodeEmail()
    {
        return $this;
    }

    /**
     * Return an encoded email address to help against spam.
     *
     * @param string $address The email address to encode
     * @return string
     */
    public function address($address)
    {
        $xhtml = '';
        $address = (string)$address;
        $len = strlen($address);
        for ($x = 0; $x &lt; $len; $x++) {
            if (preg_match('!\w!', $address[$x])) {
                $xhtml .= '%' . bin2hex($address[$x]);
            } else {
                $xhtml .= $address[$x];
            }
        }
        return $xhtml;
    }

    /**
     * Return an encoded mailto link to help against spam.
     *
     * If no link text is supplied then the email address will be used
     * (as is generally preferred).
     *
     * @param string $address The email address to encode
     * @param null|string $text Text to use for link
     * @param array $attrs Any extra attributes for link
     * @return string
     */
    public function link($address, $text = null, array $attrs = array())
    {
        $encodedtext    = '';
        $encodedaddress = $this-&gt;address($address);
        if (null === $text) {
            $text = (string)$address;
        } else {
            $text = (string)$text;
        }
        $len = strlen($text);
        for ($x = 0; $x &lt; $len; $x++) {
            $encodedtext .= '&amp;#x' . bin2hex($text[$x]).';';
        }
        $xhtml = '&lt;a href=&quot;&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#116;&amp;#111;&amp;#58;' . $encodedaddress . '&quot;';
        if (!empty($attrs)) {
            foreach ($attrs as $k =&gt; $v) {
                $xhtml .= ' ' . $this-&gt;view-&gt;escape($k) . '=&quot;' . $this-&gt;view-&gt;escape($v) . '&quot;';
            }
        }
        $xhtml .= '&gt;' . $encodedtext . '';
        return $xhtml;
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.amnuts.com/2008/09/23/quick-and-easy-email-encoding-view-helper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zend Framework 1.6RC1</title>
		<link>http://blog.amnuts.com/2008/08/01/zend-framework-16rc1/</link>
		<comments>http://blog.amnuts.com/2008/08/01/zend-framework-16rc1/#comments</comments>
		<pubDate>Fri, 01 Aug 2008 09:56:31 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[Dojo]]></category>
		<category><![CDATA[paginator]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[webinar]]></category>

		<guid isPermaLink="false">http://blog.amnuts.com/?p=71</guid>
		<description><![CDATA[If you haven&#8217;t heard already, Zend Framework 1.6RC1 is out and has lots of interesting new features. Finally there&#8217;s a SOAP component (seemed odd to me to have an enterprise-level framework without it!) There&#8217;s also a paginator, XML configs can have attributes, Dojo integration and lots more. It&#8217;s been out for about 10 days as [...]]]></description>
			<content:encoded><![CDATA[<p>If you haven&#8217;t heard already, <a href="http://devzone.zend.com/article/3712-Zend-Framework-1.6-Release-Candidate-1-now-available">Zend Framework 1.6RC1 is out</a> and has lots of interesting new features.  Finally there&#8217;s a SOAP component (seemed odd to me to have an enterprise-level framework without it!)  There&#8217;s also a paginator, XML configs can have attributes, Dojo integration and lots more.</p>
<p>It&#8217;s been out for about 10 days as of the time I write this, but the only new thing I&#8217;ve tried as of yet is the Zend_Paginator component.  And I must say that I am very happy with how easy it was to set up and integrate in to a site&#8230;  Essentially, I just had to pass my select object to the paginator and write a view partial to handle how it looked &#8211; it was that easy!  With the output of the pagination put in to a partial it makes the whole thing very easy to rebrand and configure to exactly how you want it to look.  This is definitely a component I&#8217;m going to be using a lot.</p>
<p>Looking forward to using the other new features, too.  There is a <a href="http://www.zend.com/en/company/news/event/webinar-what-s-new-in-zend-framework">Zend Webinar to show the new features of ZF1.6</a> coming up on the 13th August, 2008.  Also one in September to go over <a href="http://www.zend.com/en/company/news/event/webinar-zend-framework-and-dojo-integration">integrating the new Dojo features</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.amnuts.com/2008/08/01/zend-framework-16rc1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Application running really slow</title>
		<link>http://blog.amnuts.com/2008/07/15/application-running-really-slow/</link>
		<comments>http://blog.amnuts.com/2008/07/15/application-running-really-slow/#comments</comments>
		<pubDate>Tue, 15 Jul 2008 10:50:22 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[slow]]></category>
		<category><![CDATA[Tiger]]></category>

		<guid isPermaLink="false">http://blog.amnuts.com/?p=70</guid>
		<description><![CDATA[While working on an application built on Zend Framework, I experienced a really odd slow-down of the system while running on the web cluster at work as opposed to my machine at home. I couldn&#8217;t see what the issue was myself, and it seemed to baffle people on #zftalk a bit as well as work [...]]]></description>
			<content:encoded><![CDATA[<p>While working on an application built on Zend Framework, I experienced a really odd slow-down of the system while running on the web cluster at work as opposed to my machine at home.  I couldn&#8217;t see what the issue was myself, and it seemed to baffle people on #zftalk a bit as well as work colleagues.  The speed difference was quite dramatic &#8211; going from near instant on my home computer to around 30 seconds for a page display while running on the cluster.</p>
<p>Naturally, this required a fair amount of investigation&#8230;</p>
<p>It was quickly ruled out to be any fault of ZF.  After all, it is being used by companies such as IBM, Zend, Sourceforge, Fox, and more. If the framework were not suitable and produced slow results then they would obviously not use it, nor would any of you!</p>
<p>Next to be ruled out was custom code built on top of ZF.  With the exact same code-base producing faster results on one machine and not on another it was highly unlikely to be the code.</p>
<p>Profiling the code proved a little helpful.  I profiled the database connection for each query and ruled out any slowness with that as they were taking fractions of seconds.  Code profiling was a little bit more tricky, as everything seemed proportionally slower, not any one thing in particular.  However, the Zend_Loader component seemed to be taking quite some time to perform its tasks.</p>
<p>With a little command-line magic (using ktrace, kdump, grep, awk, etc. &#8211; not by me, but by talented colleague) it was determined that the OS itself, Mac OSX &#8216;Tiger&#8217;, was mainly to blame.  The cause of the problem was trying to determine relative paths and the slow speed at which Tiger was doing this&#8230;  As I understand it, to determine the current directory, &#8216;.&#8217;, the OS needs to back track all the way to the root, get the whole list of directories and work out which inode matches the one your current path is, and then work its way back down the directories until it finds a match. Once it&#8217;s done that you have your current path. If it sounds intensive, that&#8217;s because it is.</p>
<p>When comparing Tiger to Leopard we were seeing a 1000x improvement (4 microseconds as opposed to 4 milliseconds) to do various getdirentries() calls.</p>
<p>If you used the include path for a handful of files you&#8217;d never notice a significant drop in speed, but the application I&#8217;m working on, together with ZF will typically include 140+ files.</p>
<p>So how was the issue resolved?</p>
<p>For the short term there was a very simple fix; simply alter the include path so that the current path is last to be checked and the more significant paths (such as where the application or Zend library is located) are first. This simple tweak took a 30+ second load time to around two seconds &#8211; a vast improvement! Still, two seconds is not ideal so we will be having Leopard-based machine installed on the web cluster to see if that also helps to increase performance.</p>
<p>I&#8217;m curious; has anyone else had a similar problem?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.amnuts.com/2008/07/15/application-running-really-slow/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>StringToTitle filter</title>
		<link>http://blog.amnuts.com/2008/06/05/stringtotitle-filter/</link>
		<comments>http://blog.amnuts.com/2008/06/05/stringtotitle-filter/#comments</comments>
		<pubDate>Thu, 05 Jun 2008 12:38:14 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[filter]]></category>

		<guid isPermaLink="false">http://blog.amnuts.com/?p=65</guid>
		<description><![CDATA[I like the filtering capabilities of the Zend Framework, but for some reason there doesn&#8217;t seem to be a string to title case filter (though there is a string to upper and string to lower). So here it is:]]></description>
			<content:encoded><![CDATA[<p>I like the filtering capabilities of the Zend Framework, but for some reason there doesn&#8217;t seem to be a string to title case filter (though there is a string to upper and string to lower).  So here it is:</p>
<p><span id="more-65"></span></p>
<pre class="brush: php; title: ; notranslate">&lt; ?php

/**
 * @see Zend_Filter_Interface
 */
require_once 'Zend/Filter/Interface.php';

/**
 * Convert a string to titlecase.
 *
 * Seemingly missing from the core Zend distribution.
 */
class StringToTitle implements Zend_Filter_Interface
{
    /**
     * Encoding for the input string
     *
     * @var string
     */
    protected $_encoding = null;

    /**
     * Set the input encoding for the given string
     *
     * @param  string $encoding
     * @throws Zend_Filter_Exception
     */
    public function setEncoding($encoding = null)
    {
        if (!function_exists('mb_convert_case')) {
            require_once 'Zend/Filter/Exception.php';
            throw new Zend_Filter_Exception('mbstring is required for this feature');
        }
        $this-&gt;_encoding = $encoding;
    }

    /**
     * Defined by Zend_Filter_Interface
     *
     * Returns the string $value, converting characters to titlecase as necessary
     *
     * @param  string $value
     * @return string
     */
    public function filter($value)
    {
        if ($this-&gt;_encoding) {
            return mb_convert_case((string) $value, MB_CASE_TITLE, $this-&gt;_encoding);
        }
        return ucwords((string) $value);
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.amnuts.com/2008/06/05/stringtotitle-filter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Auto generating basic models for a Zend Framework app</title>
		<link>http://blog.amnuts.com/2008/04/11/auto-generating-basic-models-for-a-zend-framework-app/</link>
		<comments>http://blog.amnuts.com/2008/04/11/auto-generating-basic-models-for-a-zend-framework-app/#comments</comments>
		<pubDate>Fri, 11 Apr 2008 13:18:39 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Code snippets]]></category>
		<category><![CDATA[Experiments]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[models]]></category>

		<guid isPermaLink="false">http://blog.amnuts.com/2008/04/11/auto-generating-basic-models-for-a-zend-framework-app/</guid>
		<description><![CDATA[Do you have a database with foreign keys and just wish you could have something automatically create your ZF models from it? Well, today that was me. So as a little proof of concept, this is the code I came up with to do it for me&#8230; But before we get to that, a few [...]]]></description>
			<content:encoded><![CDATA[<p>Do you have a database with foreign keys and just wish you could have something automatically create your ZF models from it? Well, today that was me. So as a little proof of concept, this is the code I came up with to do it for me&#8230;</p>
<p>But before we get to that, a few caveats:</p>
<ul>
<li>It&#8217;s just a proof of concept</li>
<li>The output needs updating for proper reference names, etc.</li>
<li>Outputs everything to screen in one go and doesn&#8217;t save the files.</li>
</ul>
<p>However, it might be handy to someone, so I post it up for your comments.<br />
<span id="more-63"></span></p>
<pre class="brush: php; title: ; notranslate">&lt; ?php

require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();

$config = array(
	'host'	 =&gt; 'localhost',
	'username' =&gt; 'myusername',
	'password' =&gt; 'mypassword',
	'dbname'   =&gt; 'mydbname'
);
try {
	$db = Zend_Db::factory('pdo_mysql', $config);
} catch (Zend_Db_Exception $e) {
	echo $e-&gt;getMessage();
	die;
}

$model = &lt; &lt;&lt;EOT
&lt;?php

class %s extends Zend_Db_Table_Abstract
{
	protected \$_name = '%s';
%s
}
EOT;

$refmap_outer = &lt;&lt;&lt;EOT
	protected \$_referenceMap	= array(
%s
	);
EOT;

$refmap_inner = &lt;&lt;&lt;EOT
		'%s' =&gt; array(
			'columns'		   =&gt; array('%s'),
			'refTableClass'	 =&gt; '%s',
			'refColumns'		=&gt; array('%s')
		)
EOT;

$toTable = new Zend_Filter_Inflector(
	':tbl',
	array(':tbl' =&gt; array('Word_CamelCaseToUnderscore', 'StringToLower'))
);

$toClass = new Zend_Filter_Inflector(
	':tbl',
	array(':tbl' =&gt; array('StringToLower', 'Word_UnderscoreToCamelCase'))
);

foreach ($db-&gt;listTables() as $table) {
	$sql = &quot;
		select
			tc.constraint_name,
			kcu.table_name,
			kcu.column_name,
			kcu.referenced_table_name,
			kcu.referenced_column_name
		from
			information_schema.table_constraints tc,
			information_schema.key_column_usage kcu
		where
			tc.table_name = &quot; . $db-&gt;quote($table) . &quot;
			and tc.constraint_type = 'FOREIGN KEY'
			and kcu.constraint_name = tc.constraint_name
		&quot;;
	$keys = $db-&gt;fetchAll($sql);

	$refs = array();
	if (!empty($keys)) {
		$r = 0;
		foreach ($keys as $key) {
			$refs[] = sprintf($refmap_inner,
					'ref' . ++$r,
					$key['column_name'],
					$toClass-&gt;filter(array('tbl' =&gt; $key['referenced_table_name'])),
					$key['referenced_column_name']
				);
		}
	}
	printf($model,
		$toClass-&gt;filter(array('tbl' =&gt; $table)),
		$toTable-&gt;filter(array('tbl' =&gt; $table)),
		(!empty($refs) ? sprintf($refmap_outer, join(&quot;,\n&quot;, $refs)) : '')
	);
}
</pre>
<p>So assuming I had a database structure like:</p>
<pre class="brush: sql; title: ; notranslate">--
-- Table structure for table `users`
--
CREATE TABLE `users` (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `added` datetime NOT NULL,
  `username` varchar(32) NOT NULL,
  `password` varchar(64) NOT NULL,
  `name_first` varchar(32) NOT NULL,
  `name_last` varchar(32) NOT NULL,
  `name_nick` varchar(32) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `user_tags`
--
CREATE TABLE `user_tags` (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `user_id` int(10) UNSIGNED NOT NULL,
  `tag_user_id` int(10) UNSIGNED NOT NULL,
  `tag` varchar(24) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `tag` (`tag`),
  KEY `fk_user_tags_user_id` (`user_id`),
  KEY `fk_user_tags_tag_user_id` (`tag_user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Constraints for table `user_tags`
--
ALTER TABLE `user_tags`
  ADD CONSTRAINT `fk_user_tags_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `fk_user_tags_tag_user_id` FOREIGN KEY (`tag_user_id`) REFERENCES `users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;</pre>
<p>it would output something like:</p>
<pre class="brush: php; title: ; notranslate">&lt; ?php

class UserTags extends Zend_Db_Table_Abstract
{
	protected $_name = 'user_tags';
	protected $_referenceMap	= array(
		'ref1' =&gt; array(
			'columns'		   =&gt; array('user_id'),
			'refTableClass'	 =&gt; 'Users',
			'refColumns'		=&gt; array('id')
		),
		'ref2' =&gt; array(
			'columns'		   =&gt; array('tag_user_id'),
			'refTableClass'	 =&gt; 'Users',
			'refColumns'		=&gt; array('id')
		)
	);
}

&lt;?php

class Users extends Zend_Db_Table_Abstract
{
	protected $_name = 'users';
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.amnuts.com/2008/04/11/auto-generating-basic-models-for-a-zend-framework-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Force a file download</title>
		<link>http://blog.amnuts.com/2007/10/24/force-a-file-download/</link>
		<comments>http://blog.amnuts.com/2007/10/24/force-a-file-download/#comments</comments>
		<pubDate>Wed, 24 Oct 2007 12:03:01 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Code snippets]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[snippet]]></category>

		<guid isPermaLink="false">http://blog.amnuts.com/2007/10/24/force-a-file-download/</guid>
		<description><![CDATA[Here&#8217;s a small function that will allow you to force a file download. Very easy to use, too! Here are some examples of how you might call the function:]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a small function that will allow you to force a file download.</p>
<pre class="brush: php; title: ; notranslate">/**
 * Force a file download via HTTP.
 *
 * File is required to be on the same server and accessible via a path.
 * If the file cannot be found or some other error occurs then a
 * '204 No content' header is sent.
 *
 * @param string $path Path and file name
 * @param string $name Name of file when saved on user's computer,
 *                     null for basename from path
 * @param string $type Content type header info (e.g., 'application/vnd.ms-excel')
 * @return void
 * @access public
 */
/* public static */ function download($path, $name = null, $type = 'binary/octet-stream')
{
    if (headers_sent()) {
        echo 'File download failure: HTTP headers have already been sent and cannot be changed.';
        exit;
    }

    $path = realpath($path);
    if ($path === false || !is_file($path) || !is_readable($path)) {
        header('HTTP/1.0 204 No Content');
        exit;
    }

    $name = (empty($name)) ? basename($path) : $name;
    $size = filesize($path);

    header('Expires: Mon, 20 May 1974 23:58:00 GMT');
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
    header('Cache-Control: no-store, no-cache, must-revalidate');
    header('Cache-Control: post-check=0, pre-check=0', false);
    header('Cache-Control: private');
    header('Pragma: no-cache');
    header(&quot;Content-Transfer-Encoding: binary&quot;);
    header(&quot;Content-type: {$type}&quot;);
    header(&quot;Content-length: {$size}&quot;);
    header(&quot;Content-disposition: attachment; filename=\&quot;{$name}\&quot;&quot;);
    readfile($path);
    exit;
}</pre>
<p>Very easy to use, too!  Here are some examples of how you might call the function:</p>
<pre class="brush: php; title: ; notranslate">download('./myfile.txt');

download(__FILE__, 'a file for you.php');

download('/home/you/files/spreadsheet.xml', 'ssheet_' . date('Ymd'), 'application/vnd.ms-excel');</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.amnuts.com/2007/10/24/force-a-file-download/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple image view helper for Zend Framework</title>
		<link>http://blog.amnuts.com/2007/10/03/simple-image-view-helper-for-zend-framework/</link>
		<comments>http://blog.amnuts.com/2007/10/03/simple-image-view-helper-for-zend-framework/#comments</comments>
		<pubDate>Wed, 03 Oct 2007 11:35:51 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Code snippets]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[view helper]]></category>

		<guid isPermaLink="false">http://blog.amnuts.com/2007/10/03/simple-image-view-helper-for-zend-framework/</guid>
		<description><![CDATA[Here&#8217;s a simply view helper for the Zend Framework that can be used to display image tags. It checks to see if the image file exists and if not then it&#8217;ll use the data url scheme to output a very simple image that, ironically, says &#8216;NO IMG&#8217; on it. Please note, though, that I&#8217;ve only [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a simply view helper for the Zend Framework that can be used to display image tags.  It checks to see if the image file exists and if not then it&#8217;ll use the <a href="http://tools.ietf.org/html/rfc2397">data url scheme</a> to output a very simple image that, ironically, says &#8216;NO IMG&#8217; on it. <img src='http://blog.amnuts.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />   Please note, though, that I&#8217;ve only seen Firefox support this scheme, as wonderful as it is!</p>
<p><span id="more-56"></span></p>
<pre class="brush: php; title: ; notranslate">&lt;?php

class Zend_View_Helper_Img extends Zend_View_Helper_Abstract
{
    protected $_baseurl = null;
    protected $_exists = array();

    /**
     * Constructor
     */
    public function __construct()
    {
        $url = Zend_Controller_Front::getInstance()-&gt;getRequest()-&gt;getBaseUrl();
        $root = '/' . trim($url, '/');
        if ('/' == $root) {
            $root = '';
        }
        $this-&gt;_baseurl = $root . '/';
    }

    /**
     * Output the &lt;img /&gt; tag
     *
     * @param string $path
     * @param array $params
     * @return string
     */
    public function img($path, $params = array())
    {
        $plist = array();
        $paramstr = null;
        $imagepath = $this-&gt;_baseurl . ltrim($path, '/');
        if (!isset($this-&gt;_exists[$path])) {
            $this-&gt;_exists[$path] = file_exists(realpath($_SERVER['DOCUMENT_ROOT'] . '/' . $imagepath));
        }
        if (!isset($params['alt'])) {
            $params['alt'] = '';
        }
        foreach ($params as $param =&gt; $value) {
            $plist[] = $param . '=&quot;' . $this-&gt;view-&gt;escape($value) . '&quot;';
        }
        $paramstr = ' ' . join(' ', $plist);
        return '&lt;img src=&quot;' .
                (($this-&gt;_exists[$path])
                    ? $this-&gt;_baseurl . ltrim($path, '/')
                    : 'data:image/gif;base64,R0lGODlhFAAUAIAAAAAAAP///yH5BAAAAAAALAAAAAAUABQAAAI5jI+pywv4DJiMyovTi1srHnTQd1BRSaKh6rHT2cTyHJqnVcPcDWZgJ0oBV7sb5jc6KldHUytHi0oLADs=') .
                '&quot;' . $paramstr . ' /&gt;';
    }
}</pre>
<p>Usage is really easy:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php echo $this-&gt;img('/images/logo.png', array('id' =&gt; 'logo', 'title' =&gt; 'Cool Company')); ?&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.amnuts.com/2007/10/03/simple-image-view-helper-for-zend-framework/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

