<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
	<title>Tim Fountain: Blog</title>
	<link href="http://tfountain.co.uk/" />
	<updated>2009-05-11T21:03:54+01:00</updated>
	<author>
		<name>Tim Fountain</name>
 	</author>
 	<id>http://tfountain.co.uk/</id>
	<link rel="self" href="http://feeds.feedburner.com/tim-fountain-blog-web" type="application/atom+xml" /><entry>
		<title>Deploying Zend Framework apps with Capistrano</title>
		<link href="http://feedproxy.google.com/~r/tim-fountain-blog-web/~3/Qwmp-X8FaBU/" />
		<id>http://tfountain.co.uk/blog/2009/5/11/zend-framework-capistrano-deployment/</id>
		<updated>2009-05-11T21:03:54+01:00</updated>
		<summary type="html">&lt;p&gt;One of the good things the Ruby community has brought us is &lt;a href="http://www.capify.org/"&gt;Capistrano&lt;/a&gt;, a command line tool for automated deployment. Although it was written for Rails apps, it can be used with other languages, as proven by a &lt;a href="http://www.simplisticcomplexity.com/2006/08/16/automated-php-deployment-with-capistrano/"&gt;blog post&lt;/a&gt; from a few years ago detailing how to use it to deploy PHP code. I thought I'd update this to show how it can be used to deploy Zend Framework applications.&lt;/p&gt;

&lt;p&gt;If you're not familiar with Capistrano, once it's all setup you'll be able to run:&lt;/p&gt;

&lt;pre&gt;cap production deploy&lt;/pre&gt;

&lt;p&gt;from your ZF project folder. This will automatically login to your remote server, checkout a copy of your code, run any custom tasks (e.g. setting permissions), and then switch the live site to point at the new release. If anything goes wrong with any of these steps, the deployment will stop, the new checkout will be removed, and your site will remain exactly as it is. This allows you to very easily deploy code updates and new versions with basically no downtime.&lt;/p&gt;

&lt;p&gt;I'm going to assume you already have Capistrano installed (if not, there are plenty of guides around for this). You'll also need the &lt;tt&gt;capistrano-ext&lt;/tt&gt; gem for the multistage stuff I'm going to mention later. For reference, at the time of writing I have versions capistrano 2.5.5 and capistrano-ext 1.2.1 of these gems.&lt;/p&gt;

&lt;p&gt;Capistrano has a command &lt;tt&gt;capify&lt;/tt&gt; which creates the files it requires, however this doesn't work with ZF applications because the file structure is slightly different. So we're going to create these files manually. If you're using the recommended ZF application structure (i.e. you have an &lt;tt&gt;application/configs&lt;/tt&gt; folder), I've packaged up my examples below into an &lt;a href="/files/blog/631.zip"&gt;archive&lt;/a&gt; you can just extract into the root folder of your ZF project, but read on anyway so you know what the files do.&lt;/p&gt;

&lt;p&gt;The first of these is &lt;tt&gt;Capfile&lt;/tt&gt;, which needs to live in the root directory of your ZF project. This should look something like this:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;load 'deploy' if respond_to?(:namespace) # cap2 differentiator
load 'application/configs/deploy'&lt;/pre&gt;

&lt;p&gt;this file simply loads in your main deployment configuration which in the above example will be &lt;tt&gt;application/configs/deploy.rb&lt;/tt&gt;. If you aren't using the standard ZF app structure, adjust this path to point at wherever you want your deployment configuration to live.&lt;/p&gt;

&lt;p&gt;The next file is &lt;tt&gt;deploy.rb&lt;/tt&gt;, which is where most of the deployment settings live and is the file referenced above. Create this file in your &lt;tt&gt;application/configs&lt;/tt&gt; folder. Here's an example:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
# general settings
default_run_options[:pty] = true
set :use_sudo, false

# source control settings
set :scm, :git
set :deploy_via, :remote_cache
set :repository, "ssh://git@example.com/yourapp.git"

# stages
set :stages, %w(staging production)
set :stage_dir, "application/configs/deploy"
require 'capistrano/ext/multistage' 


namespace :deploy do

  task :migrate do
    # overrides the standard Rails database migrations task
  end

  task :start, :roles =&gt; :app do

  end

  task :stop, :roles =&gt; :app do

  end

  task :restart, :roles =&gt; :app do
    # no restart required for Apache/mod_php
  end 

end
&lt;/pre&gt;

&lt;p&gt;Adjust the source control section to contain details for the repository your application lives in. The example above shows typical settings for a git repo (replace git@example.com/yourapp.git with your clone URL). If you're using Subversion, try something like this:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
set :scm, :subversion
set :repository, "svn+ssh://example.com/yourapp/trunk"
set :scm_username, "your_svn_username"
set :scm_password, "your_svn_password"
set :deploy_via, :export
&lt;/pre&gt;

&lt;p&gt;The stages section allows you to define a number of different environments for your application. In my example I'm defining two stages - production and staging. You then need a file for each which contains the appropriate login details. &lt;tt&gt;:stages_dir&lt;/tt&gt; defines where these files live, in my example it's &lt;tt&gt;application/configs/deploy/&lt;/tt&gt;. These files need to be named the same as your stages (with a .rb extension), e.g. &lt;tt&gt;production.rb&lt;/tt&gt;. Here's an example:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
role :app, "example.com"
role :web, "example.com"
role :db, "example.com", :primary =&gt; true

set :deploy_to, "/path/to/your/app/"

set :user, "your_ssh_user"
set :password, "your_ssh_password"
&lt;/pre&gt;

&lt;p&gt;Set &lt;tt&gt;:app&lt;/tt&gt; to be the hostname of your remote server. &lt;tt&gt;:web&lt;/tt&gt; and &lt;tt&gt;:db&lt;/tt&gt; will usually be the same, unless your have separate dedicated servers for each of these and need to run any custom tasks on them later. &lt;tt&gt;:deploy_to&lt;/tt&gt; should be the full path to the location on your remote server where you want your application to live. Change &lt;tt&gt;:user&lt;/tt&gt; and &lt;tt&gt;:password&lt;/tt&gt; to be the SSH login details for your remote server.&lt;/p&gt;

&lt;p&gt;To add a new stage, simply add it to the &lt;tt&gt;:stages&lt;/tt&gt; variable in &lt;tt&gt;deploy.rb&lt;/tt&gt; (&lt;code&gt;%w(staging production)&lt;/code&gt; is the Ruby equivalent of &lt;code&gt;array('staging', 'production')&lt;/code&gt;), and then create a file in &lt;tt&gt;application/configs/deploy/&lt;/tt&gt; with the appropriate login details.&lt;/p&gt;

&lt;p&gt;The &lt;tt&gt;deploy.rb&lt;/tt&gt; example above also contains a section that overrides the default Capistrano tasks &lt;tt&gt;:migrate&lt;/tt&gt;, &lt;tt&gt;:start&lt;/tt&gt;, &lt;tt&gt;:stop&lt;/tt&gt; and &lt;tt&gt;:restart&lt;/tt&gt;. These are pretty Rails-specific, so we override them because we don't need them. However if you have any custom restart requirements you'd define them here. E.g. if you're using APC with stat set to 0, you might want to add some code to the :restart task to restart Apache (this will run after each deployment).&lt;/p&gt;

&lt;p&gt;Assuming you've got all that setup correctly, it's time to give it a try. (Remember these commands will be performing actions on your remote server!) First run:&lt;/p&gt;

&lt;pre&gt;cap production deploy:setup&lt;/pre&gt;

&lt;p&gt;this will create default Capistrano folders on your remote server. After running it, login to your remote server and in your &lt;tt&gt;:deploy_to&lt;/tt&gt; location you should see two folders: releases, and shared. Then (from your local machine again), run:&lt;/p&gt;

&lt;pre&gt;cap production deploy:cold&lt;/pre&gt;

&lt;p&gt;this will run the first full deployment of your application. If you check your remote server again, you'll find a new timestamped folder in the releases folder that contains a full copy of your code. You'll also see a 'current' symlink at the &lt;tt&gt;:deploy_to&lt;/tt&gt; location that symlinks to the latest release. So just set your vhost to point at (your path)current/public and your site should be up and running!&lt;/p&gt;

&lt;p&gt;Then in future, to deploy a new update you just have to run:&lt;/p&gt;

&lt;pre&gt;cap production deploy&lt;/pre&gt;

&lt;p&gt;this will checkout a new copy of the code, and assuming no problems, switch the 'current' symlink to point at the new release. And that's it! To perform the same thing on your staging setup (or any other stages you add), simple replace 'production' with the name of the stage in the commands above. E.g. cap &lt;tt&gt;staging&lt;/tt&gt; deploy.&lt;/p&gt;

&lt;p&gt;Hopefully that should be enough to get you started. Run &lt;tt&gt;cap -T&lt;/tt&gt; from your ZF project folder to see what other commands you can use, and the &lt;a href="http://wiki.capify.org/index.php/Frequently_Asked_Questions"&gt;Capistrano FAQ&lt;/a&gt; is a good place to start if you need to customise anything.&lt;/p&gt;</summary>
	<feedburner:origLink>http://tfountain.co.uk/blog/2009/5/11/zend-framework-capistrano-deployment/</feedburner:origLink></entry>
	<entry>
		<title>Optimizing server configuration for PHP applications</title>
		<link href="http://feedproxy.google.com/~r/tim-fountain-blog-web/~3/yacmuPYzO8Q/" />
		<id>http://tfountain.co.uk/blog/2009/4/23/optimizing-server-configuration-php/</id>
		<updated>2009-05-08T18:47:54+01:00</updated>
		<summary type="html">&lt;p&gt;We recently migrated all of our websites to some new servers, and for the first time we have some dedicated servers for our PHP CMS platform. This gave me the opportunity to fine tune configuration specifically for PHP, and I was surprised at how much difference could be made without even touching the application code.&lt;/p&gt;&lt;p&gt;The setup includes two web servers and a dedicated MySQL server, all with 1G of RAM, running CentOS. I was using Apache bench for the tests, with the parameters &lt;tt&gt;ab -c 10 -n 500 http://www.example.com/&lt;/tt&gt; (10 concurrent requests, 500 in total). The starting point was a standard yum-installed LAMP setup except for the addition of the &lt;a href="http://blog.famillecollet.com/pages/Config-en"&gt;Remi&lt;/a&gt; repositories for more recent PHP packages (PHP 5.2.9, MySQL 5.0.45, Apache 2.2.3).&lt;/p&gt;&lt;p&gt;If you&amp;#39;re not familiar with Apache bench, the &amp;#39;requests per second&amp;#39; stat is the thing to look out for in the results, higher is better. Each test was run after &amp;#39;warming up&amp;#39; the caches, and there weren&amp;#39;t any failed requests.&lt;/p&gt;&lt;p&gt;Firstly the baseline test (fresh after installation):&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Requests per second:&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;13.31&lt;/b&gt; [#/sec] (mean)&lt;br /&gt;Time per request:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 751.477 [ms] (mean)&lt;br /&gt;Time per request:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 75.148 [ms] (mean, across all concurrent requests)&lt;br /&gt;Transfer rate:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 43.27 [Kbytes/sec] received&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Then after installing APC:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Requests per second:&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;18.52&lt;/b&gt; [#/sec] (mean)&lt;br /&gt;Time per request:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 539.833 [ms] (mean)&lt;br /&gt;Time per request:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 53.983 [ms] (mean, across all concurrent requests)&lt;br /&gt;Transfer rate:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 60.24 [Kbytes/sec] received&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Then started the tweaking. The Remi php-apc package has &lt;tt&gt;apc.shm_size&lt;/tt&gt; set to 32M by default (slightly higher than the PHP default of 30M). As I understand it, this variable controls how much RAM is reserved by APC. If it is set too low, APC won&amp;#39;t be able to cache all of your commonly included PHP files; but as you increase it, once you pass the point at which your whole app can be cached you&amp;#39;ll start to see a reduction in performance, since you&amp;#39;re reducing the amount of memory that can be used by Apache. After some experimentation I kept this at 32M.&lt;/p&gt;&lt;p&gt;Next I turned off &lt;tt&gt;apc.stat&lt;/tt&gt;. With this option enabled APC checks the last modified time of each included PHP script on each request to see if it needs to be recompiled. With it off you save quite a lot of file system calls, especially if you have a lot of file includes, but it means you need to restart Apache after any code changes. Results:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Requests per second:&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;18.89&lt;/b&gt; [#/sec] (mean)&lt;br /&gt;Time per request:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 529.346 [ms] (mean)&lt;br /&gt;Time per request:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 52.935 [ms] (mean, across all concurrent requests)&lt;br /&gt;Transfer rate:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 61.43 [Kbytes/sec] received&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Not much difference! The application code in this case is stored on a shared NFS drive, so perhaps the local NFS client is caching some of the file information.&lt;/p&gt;&lt;p&gt;Next I enabled &lt;tt&gt;apc.include_once_override&lt;/tt&gt;, which gets around the problem APC used to have caching files included using include_once or require_once:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Requests per second:&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;23.00&lt;/b&gt; [#/sec] (mean)&lt;br /&gt;Time per request:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 434.698 [ms] (mean)&lt;br /&gt;Time per request:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 43.470 [ms] (mean, across all concurrent requests)&lt;br /&gt;Transfer rate:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 74.81 [Kbytes/sec] received&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;If your application uses Zend Framework you&amp;#39;ll probably see even more benefit here, since ZF uses include_once extensively.&lt;/p&gt;&lt;p&gt;Next came the MySQL tweaking. Although MySQL comes with some suggested configuration files for different setups, the defaults are quite conservative. If you&amp;#39;re not familiar with the different MySQL config options, I&amp;#39;d suggest installing &lt;a href="http://wiki.mysqltuner.com/MySQLTuner"&gt;MySQLTuner&lt;/a&gt;, a free script you can run which will analyse your installation and suggest some changes.&lt;/p&gt;&lt;p&gt;By far the biggest improvements you can make are enabling the query cache and increasing &lt;tt&gt;key_buffer_size&lt;/tt&gt;. If you&amp;#39;re running a dedicated server for MySQL you can assign a decent chunk of RAM to these two. The settings I used:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;key_buffer_size=128M&lt;br /&gt;query_cache_size=256M&lt;br /&gt;query_cache_limit=16M&lt;br /&gt;thread_cache_size=4&lt;br /&gt;table_cache=128&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Results:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Requests per second:&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;61.60&lt;/b&gt; [#/sec] (mean)&lt;br /&gt;Time per request:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 162.339 [ms] (mean)&lt;br /&gt;Time per request:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 16.234 [ms] (mean, across all concurrent requests)&lt;br /&gt;Transfer rate:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 199.42 [Kbytes/sec] received&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Big improvement!&lt;/p&gt;&lt;p&gt;Obviously there are a number of application-level things that can be done to improve performance further (page/fragment caching, caching objects in APC/memcache), but this shows how much improvement you can gain just by tweaking some config files.&lt;/p&gt;</summary>
	<feedburner:origLink>http://tfountain.co.uk/blog/2009/4/23/optimizing-server-configuration-php/</feedburner:origLink></entry>
	<entry>
		<title>Experiences with Zend_Captcha_Image</title>
		<link href="http://feedproxy.google.com/~r/tim-fountain-blog-web/~3/FnvZapY5HlE/" />
		<id>http://tfountain.co.uk/blog/2009/1/6/zend-captcha-image-experiences/</id>
		<updated>2009-01-06T23:48:34+00:00</updated>
		<summary type="html">&lt;p&gt;Yesterday I had to add a CAPTCHA to a form on a site already using some ZF components, which gave me a chance to try out the CAPTCHA component in ZF.&lt;/p&gt;&lt;p&gt;As well as the usual obfuscated image, Zend_Captcha supports figlet (ASCII words) and reCAPTCHA (a 3rd party CAPTCHA service to help transcribing old books). Although I love the idea of reCAPTCHA, I&amp;#39;ve always thought its standard input box looks a bit like a banner advert (and thus is &lt;a href="http://en.wikipedia.org/wiki/Banner_blindness"&gt;easy to miss&lt;/a&gt;), so I went with the familiar squiggly image (Zend_Captcha_Image).&lt;/p&gt;&lt;p&gt;Most of the standalone CAPTCHA scripts I&amp;#39;ve used in the past work as follows: You include an image tag in your HTML which points at a PHP script. This script generates an image on the fly (and shows it), as well as storing the generated word in a session. You then include a chunk of code in your form processing script that checks the submitted data against the session word.&lt;/p&gt;&lt;p&gt;The ZF component works slightly differently, in that it generates an actual image file (stored on the file system), and then outputs an image tag that points at this. The generated word is stored in the session (using Zend_Session), and the object has a method for comparing the two when the form is submitted.&lt;/p&gt;&lt;p&gt;Although not a requirement, the component was obviously designed to be used in conjunction with Zend_Form, and it took some digging around in the code to work out how to use it without. Certainly the code example in the docs is incomplete, so hopefully this article will help anyone trying to do the same.&lt;/p&gt;&lt;p&gt;Firstly the absolute minimum amount of code required to generate (and show) a CAPTCHA image:&lt;/p&gt;&lt;pre name="code" class="php"&gt;&amp;lt;?php
require_once(&amp;#39;Zend/Captcha/Image.php&amp;#39;);

$captcha = new Zend_Captcha_Image(array(
        &amp;#39;font&amp;#39; =&amp;gt; &amp;#39;/path/to/fonts/Example.ttf&amp;#39;
));

$id = $captcha-&amp;gt;generate();

require_once(&amp;#39;Zend/View.php&amp;#39;);
echo $captcha-&amp;gt;render(new Zend_View());
&lt;/pre&gt;&lt;p&gt;this will create a PNG image in the folder &lt;tt&gt;images/captcha&lt;/tt&gt; (which needs to be writeable). There are garbage collection methods that will automatically remove old images after a configurable amount of time. You will need to replace the font path with the path to an actual TTF font file on your system. You can either download a free font (of which there are many on the Web), or point it at a font already installed on your server (check &lt;tt&gt;/usr/share/fonts/truetype/&lt;/tt&gt; in Ubuntu).&lt;/p&gt;&lt;p&gt;View this script in a browser and you should see an image like this:&lt;/p&gt;&lt;p&gt;&lt;img src="/images/448.png" width="200" height="50" alt="Example of a CAPTCHA image created by Zend_Captcha_Image" style="" /&gt;&lt;/p&gt;&lt;p&gt;so, now you need to wrap this in a form, provide a box for the user to enter their input, and then check this data after a post. And this is where the documentation starts to let it down, since no example of this is provided.&lt;/p&gt;&lt;p&gt;Checking the POST data is done using the function &lt;code&gt;isValid()&lt;/code&gt;, which has two parameters - &lt;code&gt;$value&lt;/code&gt; and &lt;code&gt;$context&lt;/code&gt;. &lt;code&gt;$context&lt;/code&gt; is optional, and even after looking at the code I&amp;#39;m not clear what this is for, so I&amp;#39;ve ignored it. You would assume &lt;code&gt;$value&lt;/code&gt; to be the string the user enters, but it actually needs to be an array with two keys: &lt;code&gt;input&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt;. &lt;code&gt;$value[&amp;#39;input&amp;#39;]&lt;/code&gt; should be what the user typed into the form, and &lt;code&gt;$value[&amp;#39;id&amp;#39;]&lt;/code&gt; should be the MD5 hash returned when the CAPTCHA was generated (&lt;code&gt;$id&lt;/code&gt; in my code example above).&lt;/p&gt;&lt;p&gt;If you are using this with Zend_Form, the supplied decorator will output form fields that generate this array for you. But if not, here&amp;#39;s a working example:&lt;/p&gt;&lt;pre name="code" class="php"&gt;&amp;lt;?php
require_once(&amp;#39;Zend/Captcha/Image.php&amp;#39;);

$captcha = new Zend_Captcha_Image(array(
        &amp;#39;font&amp;#39; =&amp;gt; &amp;#39;/path/to/fonts/Example.ttf&amp;#39;
));

if (!empty($_POST)) {
        if ($captcha-&amp;gt;isValid($_POST[&amp;#39;captcha&amp;#39;])) {
                echo &amp;#39;Passed CAPTCHA check&amp;#39;;
        }
}

$id = $captcha-&amp;gt;generate();
?&amp;gt;

&amp;lt;form method=&amp;quot;post&amp;quot; action=&amp;quot;&amp;quot;&amp;gt;
&amp;lt;?php
require_once(&amp;#39;Zend/View.php&amp;#39;);
echo $captcha-&amp;gt;render(new Zend_View());
?&amp;gt;

&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;captcha[input]&amp;quot; /&amp;gt;
&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;captcha[id]&amp;quot; value=&amp;quot;&amp;lt;?=$id?&amp;gt;&amp;quot; /&amp;gt;

&amp;lt;input type=&amp;quot;submit&amp;quot; name=&amp;quot;submit&amp;quot; value=&amp;quot;Submit&amp;quot; /&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/pre&gt;&lt;p&gt;It&amp;#39;s important that the &lt;code&gt;isValid()&lt;/code&gt; check happens before the &lt;code&gt;generate()&lt;/code&gt; (as in the example above), as otherwise you&amp;#39;ll be checking against a new CAPTCHA and the check will always fail. Normally you would only run the &lt;code&gt;generate()&lt;/code&gt; on non-POST requests, or if the check fails (to give the user a fresh image to try).&lt;/p&gt;&lt;p&gt;A number of other options can be supplied to customise the image, e.g.:&lt;/p&gt;&lt;pre name="code" class="php"&gt;&amp;lt;?php
$captcha = new Zend_Captcha_Image(array(
        &amp;#39;wordLen&amp;#39; =&amp;gt; 5,
        &amp;#39;font&amp;#39; =&amp;gt; &amp;#39;/path/to/fonts/Example.ttf&amp;#39;,
        &amp;#39;imgDir&amp;#39; =&amp;gt; &amp;#39;./captcha/&amp;#39;,
        &amp;#39;imgUrl&amp;#39; =&amp;gt; &amp;#39;/captcha/&amp;#39;,
        &amp;#39;width&amp;#39; =&amp;gt; 150,
        &amp;#39;height&amp;#39; =&amp;gt; 55,
        &amp;#39;dotNoiseLevel&amp;#39; =&amp;gt; 40,
        &amp;#39;lineNoiseLevel&amp;#39; =&amp;gt; 3
));&lt;/pre&gt;&lt;p&gt;&lt;code&gt;wordLen&lt;/code&gt; controls the number of characters in the image (default is 8). &lt;code&gt;imgDir&lt;/code&gt; and &lt;code&gt;imgUrl&lt;/code&gt; control where the image files are stored. &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; affect the dimensions of the generated image. &lt;code&gt;dotNoiseLevel&lt;/code&gt; and &lt;code&gt;lineNoiseLevel&lt;/code&gt; control the number of dots and lines added.&lt;/p&gt;</summary>
	<feedburner:origLink>http://tfountain.co.uk/blog/2009/1/6/zend-captcha-image-experiences/</feedburner:origLink></entry>
	<entry>
		<title>Maintainable CSS</title>
		<link href="http://feedproxy.google.com/~r/tim-fountain-blog-web/~3/LAJLFx-ZDEk/" />
		<id>http://tfountain.co.uk/blog/2008/10/2/maintainable-css/</id>
		<updated>2008-10-08T22:39:23+01:00</updated>
		<summary type="html">&lt;p&gt;Natalie Down has put up slides for what looked like an interesting presentation on &lt;a href="http://natbat.net/2008/Sep/28/css-systems/"&gt;writing maintainable CSS&lt;/a&gt;. This is one of those topics that rarely gets much attention, so it&amp;#39;s nice to see some suggested good practices, particularly for stylesheet structure and layout. She also has some good tips on CSS implementations in general.&lt;/p&gt;&lt;p&gt;The biggest problem I&amp;#39;ve found when maintaining CSS is that when you come back to a site some time after the initial implementation (or if you&amp;#39;re maintaining some code written by someone else), it&amp;#39;s usually easiest to add new styles to the end of the existing stylesheet instead of reminding yourself how it all fits together, and then putting the new styles in the correct place. This gradually leads to bloat, as you end up putting in overrides for rules you&amp;#39;ve defined elsewhere, and then the next time it becomes overrides for your overrides, and so on. Grouping your rules as Natalie suggests is the only real solution to this, as it forces you to insert your code at the appropriate place, which in turn encourages to you edit what is already there instead of adding to it.&lt;/p&gt;&lt;h4&gt;Some other random notes on the slides:&lt;/h4&gt;&lt;p&gt;It&amp;#39;s interesting seeing other developers&amp;#39; approaches to design implementation. After some basic planning I tend to start chopping straight from an actual-size mockup provided by the designer, the aim being to end up with as close a representation of this graphic as possible.&lt;/p&gt;&lt;p&gt;Perhaps I&amp;#39;m interpreting it incorrectly, but &amp;quot;the grid&amp;quot; is not a phrase I&amp;#39;m particular fond of in this context - elements of a design rarely translate perfectly to a grid-type layout, and even slight changes in the spacing between elements (in order to conform to your grid) will usually result in some pretty negative feedback from the designer.&amp;nbsp;&lt;/p&gt;&lt;p&gt;I tend to think of layouts more as collections of boxes. E.g. if this site had been designer by a proper designer (obviously it hasn&amp;#39;t) and they&amp;#39;d sent you this layout as a graphic, by looking at it you&amp;#39;d put mental boxes around distinct elements such as the right sidebar, navigation and main content area. These then translate directly to semantically named divs in your layout. For more complex layouts, it can help to use the draggable line guides most graphic programs provide in order to work out exactly what lines up with what.&lt;/p&gt;&lt;p&gt;Regarding CSS frameworks, it&amp;#39;s nice to see someone speak out against these. We&amp;#39;ve been experimenting with Blueprint a bit at work and I haven&amp;#39;t been too impressed so far.&lt;/p&gt;&lt;p&gt;On the plus side I can see the attraction of something that resets browser defaults to a common baseline (particularly to people who&amp;#39;ve been stuck by browser inconsistency issues before), and I think grid-style layouts are a little easier for people to get their head round than floats and clears. But to me the negatives far outweigh these advantages:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;You&amp;#39;re adding a layer of overhead to your site - every user has to download all that additional CSS code, plus (generally) slightly larger HTML files&lt;/li&gt;&lt;li&gt;These frameworks steer you away from good markup, as your classes end up being presentational (&amp;quot;span-36 last&amp;quot;) rather than semantic (&amp;quot;navigation&amp;quot;).&lt;/li&gt;&lt;li&gt;You&amp;#39;re setting yourself up for maintainability problems (as Natalie mentions), as you&amp;#39;re starting off with a whole load of CSS code that was written by someone else, making the site more difficult to debug when you hit problems.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;CSS frameworks haven&amp;#39;t gained too much adoption as yet, so hopefully as the older, buggiest versions of IE continue to slowly lose market share, the demand for them will gradually disappear.&lt;/p&gt;</summary>
	<feedburner:origLink>http://tfountain.co.uk/blog/2008/10/2/maintainable-css/</feedburner:origLink></entry>
	<entry>
		<title>Module-specific models in Zend Framework</title>
		<link href="http://feedproxy.google.com/~r/tim-fountain-blog-web/~3/wbapeXULY20/" />
		<id>http://tfountain.co.uk/blog/2008/8/15/zend-framework-module-models/</id>
		<updated>2008-08-15T19:27:03+01:00</updated>
		<summary type="html">&lt;p&gt;A &lt;a href="http://phpimpact.wordpress.com/2008/08/12/loading-models-within-modules-in-the-zend-framework/"&gt;post this week on PHP::Impact&lt;/a&gt; looks at the handling of modules in ZF, particularly the issue of module-specific models. Frederico&amp;#39;s solution for this involves calling a particular function when you want to load a model. The way I solved this was a little different - I have a simple controller plugin that uses a &lt;tt&gt;dispatchLoopStartup&lt;/tt&gt; method to grab the current module name from the request and add its model directory to the PHP include_path. That way, assuming you&amp;#39;re using Zend_Loader, you can instantiate your module classes in the same way that you would any other.&lt;/p&gt;&lt;p&gt;Here&amp;#39;s a quick example of how this works (code is untested). Assuming a directory structure based on the proposed standard one in the ZF wiki:&lt;/p&gt;&lt;pre&gt;
application/
   config/
   controllers/
   layouts/
   models/
   modules/
      news/
         controllers/
         models/
         views/
   views/
data/
library/
scripts/
tests/
www/
&lt;/pre&gt;&lt;p&gt;In my bootstrap I define two constants - ZF_PATH (full path to the Zend Framework library directory), and APP_PATH (full path to the current project). I then use these to set the PHP include path initially:&lt;/p&gt;&lt;pre name="code" class="php"&gt;
set_include_path(
        get_include_path() . PATH_SEPARATOR .
        ZF_PATH . PATH_SEPARATOR .
        APP_PATH.&amp;#39;/application/models&amp;#39;
);
&lt;/pre&gt;&lt;p&gt;then I have a front controller plugin which looks something like this:&lt;/p&gt;&lt;pre name="code" class="php"&gt;
class Myapp_Plugin extends Zend_Controller_Plugin_Abstract
{
        public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
        {
                set_include_path(
                        get_include_path() . PATH_SEPARATOR .
                        APP_PATH.&amp;#39;/application/modules/&amp;#39;.$request-&amp;gt;getModuleName().&amp;#39;/models&amp;#39;
                );
        }
}
&lt;/pre&gt;&lt;p&gt;Register this plugin with your front controller and then as long as your module models follow the standard class naming conventions you don&amp;#39;t have to do anything special to load them in.&lt;/p&gt;&lt;p&gt;The only disadvantage of this approach is the performance hit of an additional directory in the include path, but I&amp;#39;m hoping this will be negated by an optcache (something I have yet to benchmark).&lt;/p&gt;&lt;p&gt;Frederico&amp;#39;s post has spawned a more general discussion on modules in ZF which I have some views on but that&amp;#39;s a topic for another post.&lt;/p&gt;</summary>
	<feedburner:origLink>http://tfountain.co.uk/blog/2008/8/15/zend-framework-module-models/</feedburner:origLink></entry>
	<entry>
		<title>Zend Framework in the enterprise</title>
		<link href="http://feedproxy.google.com/~r/tim-fountain-blog-web/~3/9nNcmfnMzig/" />
		<id>http://tfountain.co.uk/blog/2008/7/23/zend-framework-enterprise/</id>
		<updated>2008-07-24T11:11:11+01:00</updated>
		<summary type="html">&lt;p&gt;I just posted a comment on Federico Cargnelutti&amp;#39;s (excellent) &lt;a href="http://phpimpact.wordpress.com/"&gt;PHP blog&lt;/a&gt; that I feel I should expand on. The topic was Zend Framework&amp;#39;s suitability as an &amp;#39;enterprise&amp;#39; framework. Although I&amp;#39;m sure ZF is used in a number of enterprises (and I&amp;#39;ve used it for a few things over at &lt;a href="http://www.incutio.com/"&gt;Incutio&lt;/a&gt; already), I think it is still a way from being the &amp;#39;perfect&amp;#39; enterprise framework, which is how it is described in the post.&lt;/p&gt;&lt;p&gt;There are three &amp;#39;enterprisey&amp;#39; areas in which I believe it is particularly lacking:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;ORM&lt;/li&gt;&lt;li&gt;Database migrations&lt;/li&gt;&lt;li&gt;Application deployments&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;None of these things are &amp;#39;impossible&amp;#39; to do with ZF-based apps, but the ORM has its limitations; and the other two aren&amp;#39;t covered by ZF at all and require integration of third party solutions such as &lt;a href="http://phing.info/"&gt;Phing&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Zend&amp;#39;s view on component development for ZF has been that they wish to focus on areas where they feel they can offer value to the PHP community as a whole. For this reason they have delibrately avoided developing components for things already well served by existing open source PHP projects. This makes complete sense. But as a developer coming to ZF afresh, unless you already know about these projects, you&amp;#39;re going to see some pretty big holes in ZF as a platform on which to build your applications.&lt;/p&gt;&lt;p&gt;Firstly, ORM. I&amp;#39;m not going to say too much about this since I&amp;#39;ve posted about it before. I guess my main complaint about ORM in ZF is that I&amp;#39;ve found the Table Data Gateway pattern pretty limited (which isn&amp;#39;t ZF&amp;#39;s fault of course), and because of this you frequently end up having to either write your own ORM layer or turn to third party libraries such as Doctrine or Propel.&lt;/p&gt;&lt;p&gt;As an example, one of the first projects I tried with ZF was a rewrite of one our legacy applications, in which the data for domain objects frequently spans two or more database tables. The only way to load this kind of data with Zend_Db_Table is to create your own joins with Zend_Db_Table_Select, to the point where you&amp;#39;d basically back to writing raw SQL.&lt;/p&gt;&lt;p&gt;It is also suprisingly difficult to get the Zend_Db family of classes to return instances of your application&amp;#39;s classes (by default they always returns data arrays which your application then has to convert into objects). It&amp;#39;s not impossible to solve this, e.g. you can have your objects extend Zend_Db_Table_Row, or through some calls on Zend_Db_Statement directly you can specify the class you&amp;#39;d like returned, but both of these approaches are a little messy.&lt;/p&gt;&lt;p&gt;I feel a little bad bashing Zend_Db, as it does what it is supposed to do very well, and the adapter, profiler and select families of classes are all excellent. But these are real world problems that I&amp;#39;ve not found with other frameworks.&lt;/p&gt;&lt;p&gt;Secondly, database migrations. There is nothing in ZF to do these, the closest is a community-submitted proposal for a Zend_Db_Schema_Manager component which hasn&amp;#39;t been updated since November last year. Sure there are some third party solutions, but this is functionality&amp;nbsp;Rails provides out of the box.&lt;/p&gt;&lt;p&gt;Thirdly, deployments. Gone are the days when to make an app live you FTP in and manually upload the files (or at least they should be). Whilst Rails doesn&amp;#39;t provide anything like this, Capistrano (which is excellent), was written for RoR, and is very easy to install and integrate with Rails apps.&lt;/p&gt;&lt;p&gt;This has been quite a negative post. I don&amp;#39;t mean to suggest that Zend have taken the wrong approach in development of the framework - It&amp;#39;s still relatively young, and the upcoming 1.6 release does plug a few of the less-enterprisey holes. But if the framework is to be taken seriously as a platform on which to build enterprise applications, these are the areas which I feel need improving. This could be achieved either through the development of new components providing this functionality, or through components that provide much easier integration with the existing PHP solutions (in the same way that symfony has a component for interacting with Propel).&lt;/p&gt;&lt;p&gt;In an ideal world, I&amp;#39;d love to see Zend-contributed components which implement some alternative patterns for use in ORM layers, such as Zend_Data_Mapper and Zend_Active_Record (post PHP5.3) classes. I also have a close eye on the Zend_Tool project, which I hope will eventually cover the other two areas I mentioned.&lt;/p&gt;&lt;p&gt;There are also quite a few big pluses for ZF as an enterprise framework, in addition to the things Federico mentioned in his post, the license of ZF itself and Zend&amp;#39;s other offerings (training, IDE etc.) both definitely work in its favour.&lt;/p&gt;</summary>
	<feedburner:origLink>http://tfountain.co.uk/blog/2008/7/23/zend-framework-enterprise/</feedburner:origLink></entry>
</feed>
