<?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>Pale Purple</title>
	<atom:link href="http://www.palepurple.co.uk/feed" rel="self" type="application/rss+xml" />
	<link>http://www.palepurple.co.uk</link>
	<description>Business Web Application Development and Training in PHP</description>
	<lastBuildDate>Thu, 16 Feb 2012 15:06:08 +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>Fight the bulge &#8211; page load time matters</title>
		<link>http://www.palepurple.co.uk/fight-the-bulge-page-load-time-matters</link>
		<comments>http://www.palepurple.co.uk/fight-the-bulge-page-load-time-matters#comments</comments>
		<pubDate>Tue, 31 Jan 2012 10:49:36 +0000</pubDate>
		<dc:creator>palepurple</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[compression]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[deflate]]></category>
		<category><![CDATA[expiry]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[speed]]></category>

		<guid isPermaLink="false">http://www.palepurple.co.uk/?p=401</guid>
		<description><![CDATA[One often overlooked, area ripe for improvement on websites is that of page weight &#8211; namely how much data needs to be downloaded by the web browser before the page is rendered. Most web pages will be constructed from a &#8230; <a href="http://www.palepurple.co.uk/fight-the-bulge-page-load-time-matters">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>One often overlooked, area ripe for improvement on websites is that of page weight &#8211; namely how much data needs to be downloaded by the web browser before the page is rendered. Most web pages will be constructed from a mixture of Javascript, Stylesheets (CSS), Images and HTML. A <a title="BBC News - Girth of webpages increasing" href="http://www.bbc.co.uk/news/technology-16300000">BBC news article</a> states that the average page &#8216;weight&#8217; is approaching 1mb</p>
<p>Why does it matter? Well, although it&#8217;s tempting to think everyone must have pretty quick &gt;4mbit ADSL, it&#8217;s not always the case -</p>
<ol>
<li>Mobile users may be on a GPRS (2G) or 3G connection &#8211; which is normally far less than 1Mbit/s (3g minimum should be 200Kbit). At this speed our average page would take about 40 seconds to load.</li>
<li>Some people (often in rural areas) will be limited to around around 512Kb or 1Mbit &#8211; due to the long distances between themselves and the nearest telephone exchange (so around about 10 seconds to load).</li>
<li>If you&#8217;re lucky enough to have around a 10Mbit ADSL connection, then the download would take around about 1 second.</li>
</ol>
<p>We seem to be seeing mobile users accounting for around about 10-20% of the traffic to websites at the moment &#8211; and this figure is likely to grow as <a title="Apple selling more iPads than the HP sells PCs" href="http://www.reghardware.com/2012/01/31/canalys_q4_2011_figures_put_apple_on_top_over_hp/">tablet computing becomes more popular</a>. Having a mobile theme on your website is likely to help with this &#8211; so resources are loaded via AJAX (see e.g <a title="jQuery Mobile page loading" href="http://jquerymobile.com/demos/1.0.1/docs/pages/page-anatomy.html">jQueryMobile</a>)</p>
<p>From a developers point of view, there are a number of things we can do to help reduce the &#8216;weight&#8217; of a web page &#8211; for example :</p>
<ol>
<li>Enable compression on textual data being sent back by the web server using deflate or gzip (trading off some CPU time against network bandwidth) (Example below)</li>
<li>Resize images so they are not being resized in a stylesheet / by the browser &#8211; when using PHP, something like the <a title="phpimageresize" href="https://github.com/palepurple/phpimageresize">phpimageresize</a> plugin could be used (Example below)</li>
<li>Ensure static assets have appropriate / correct expiry times/headers to encourage client side caching (or caching by upstream proxy servers) (see mod_expires) (Example below)</li>
<li>Try and use &#8216;common&#8217; URLs for JS libraries (e.g. Google&#8217;s API hosting) &#8211; as there&#8217;s a reasonable chance the user will already have the script cached in their browser before visiting your site.</li>
<li>Compact or minimise stylesheets and javascript resources &#8211; removing unnecessary spaces and comments (see e.g. the <a title="Yahoo YUI Compressor" href="http://developer.yahoo.com/yui/compressor/">YUI compressor</a> )</li>
<li>Delay loading/fetching of Javascript (see e.g. the <a title="contentLoader @ jsClasses.org" href="http://www.jsclasses.org/blog/package/24/post/1-Fast-Page-Loading-Tutorial.html">contentLoader script</a> from jsclasses.org) until after the initial page has loaded.</li>
<li>Merge multiple resources together (the Google <a title="Google's mod_pagespeed Apache plugin" href="http://code.google.com/speed/page-speed/docs/module.html">mod_pagespeed</a> Apache plugin can do this) &#8211; so rather than your browser making multiple requests to the server for multiple javascript files, it sees only one.</li>
<li>Appropriate use of AJAX to load content (saving the user from having to download unchanged HTML between &#8216;pages&#8217;).</li>
</ol>
<h2>Server side data compression</h2>
<p>If you&#8217;re using Apache, enabling the &#8216;deflate&#8217; module and then having something like the following in a .htaccess file should work well -</p>
<p><code>AddOutputFilterByType DEFLATE text/css application/x-javascript text/x-component text/html</code></p>
<p>PHP can also perform the compression for you, but handling the compression through the web server will give better results (more stuff will be compressed).</p>
<h2>Image Resizing</h2>
<p>If a graphic designer has uploaded an image to the website, and it then gets resized through CSS, your browser is technically downloading more data than it needs to. Instances of this can be easily discovered using the <a title="Google Page Speed" href="https://developers.google.com/pagespeed/">Google PageSpeed tool</a>.</p>
<p>Dynamic resizing of images can be done using the <a title="phpimageresize" href="https://github.com/palepurple/phpimageresize">phpImageResize</a> tool (and I&#8217;m sure there are many other alternatives) as follows &#8211; on the assumption we want to only show a 20px x 20px image:</p>
<p><code> &lt;img src="&lt;?php echo resize('images/whatever.jpg', array('h' =&gt; 20, 'w' =&gt; 20, 'scale' =&gt; true)); ?&gt;"&gt;<br />
</code></p>
<p>For one customer we found correctly resizing the images reduced page &#8216;weight&#8217; from around about 5mb originally to 1mb (it is a very image heavy news site/blog). Such a drastic reduction will make the site feel &#8216;snappier&#8217; and more responsive to all users, save on server resources (bandwidth) and allow the server to handle more traffic at once. This should lead to more page impressions and therefore greater advertising revenue.</p>
<h2>Expiry Times</h2>
<p>Adding something like the following to a &#8216;.htaccess&#8217; file should work well, assuming Apache as your web server:</p>
<p><code> ExpiresByType text/css A7200<br />
ExpiresByType application/x-javascript A7200</code></p>
<p>Which tells the browser to cache the javascript and CSS files for 2 hours after access. Often the expiry value can be far higher &#8211; often days, or even years.</p>
<p>It&#8217;s also normally useful to turn off eTag support at this point (&#8220;FileEtag None&#8221; in .htaccess) &#8211; to try and stop browsers trying to validate whether their cache is up to date on each request.</p>
<h2>Common URLs for JS Libraries</h2>
<p>For example, rather than hosting jQuery from your own server (which is probably identical to jQuery on many other servers) you could use e.g.</p>
<p>&lt;script src=&#8221;https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js&#8221;&gt;&lt;/script&gt;</p>
<p>Which is both minified and there&#8217;s a reasonable chance the end user may already have it cached due to other websites using it. See the<a title="Google Code - jQuery etc apis" href="http://code.google.com/apis/libraries/devguide.html#jquery"> Google code site</a> for more information.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.palepurple.co.uk/fight-the-bulge-page-load-time-matters/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Circuit Breaker Design Pattern</title>
		<link>http://www.palepurple.co.uk/the-circuit-breaker-design-pattern</link>
		<comments>http://www.palepurple.co.uk/the-circuit-breaker-design-pattern#comments</comments>
		<pubDate>Thu, 12 Jan 2012 13:44:30 +0000</pubDate>
		<dc:creator>palepurple</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[training]]></category>
		<category><![CDATA[circuit breaker]]></category>
		<category><![CDATA[design pattern]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://www.palepurple.co.uk/?p=391</guid>
		<description><![CDATA[This post is based upon some content within our PHP OO training course (which covers design patterns). The circuit breaker design pattern is a fairly simple, and handy approach to dealing with remote services which may be offline. To explain &#8230; <a href="http://www.palepurple.co.uk/the-circuit-breaker-design-pattern">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This post is based upon some content within our <a title="Object Orientation training course" href="http://www.palepurple.co.uk/php-training/object-orientation">PHP OO training course</a> (which covers design patterns).</p>
<p>The <a title="Circuit Breaker Design Pattern" href="http://en.wikipedia.org/wiki/Circuit_breaker_design_pattern">circuit breaker design pattern</a> is a fairly simple, and handy approach to dealing with remote services which may be offline. To explain the pattern, here&#8217;s a semi-true story -</p>
<p>So, imagine the front page of a website includes some output from talking to twitter. However, one day twitter is offline &#8211; and all visitors to the site start to experience a 10-15 second delay in page load time. You investigate the problem and discover it&#8217;s due to Twitter being offline &#8211; in that all requests to it are timing out. What would be nice at this point in time is if your code could have known in advance that Twitter was offline and skipped making a request on it &#8211; therefore saving the end users from experiencing a page load delay.</p>
<p>In order to implement the above, we need some sort of shared state between requests &#8211; within a PHP context, we could use something like memcache or APC (both are fast and pretty simple to use).</p>
<p>So, before your code checks a remote service, it checks the circuit breaker&#8217;s status. If the circuit breaker says &#8220;ok&#8221; then your code talks to the remote service and notifies the circuit breaker of the outcome (success or failure). If more than a set number of failures occur within a set time period then the circuit breaker changes state and your code can therefore avoid experiencing whatever timeouts may have otherwise occurred.</p>
<p>Pseudo code to illustrate the above could look like :</p>
<pre class="brush:php">&lt;?php
$cb = new CircuitBreaker('talking_to_twitter');
if($cb-&gt;isOk()) {
    $url = 'http://search.twitter.com/search.json?q=cake';
    $json = @file_get_contents($url);
    if(false === $json) {
        // immediate problem with twitter -
        // tell the circuit breaker.
        $cb-&gt;fail();
    }
    else {
        // let's try and decode the data - check it's valid.
        $data = @json_decode($json);
        if(false === $data || !isset($data['completed_in'])) {
            $cb-&gt;fail();
        }
        else {
            // everything looks good... tell the circuit breaker
            // and print something trivial out.
            $cb-&gt;success();
            echo $data['results'][0]['text'];
        }
   }
}
else {
   // circuit breaker thinks twitter is ill, so don't bother trying
   echo "Sorry, twitter is down <img src='http://www.palepurple.co.uk/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' />  ";
}</pre>
<p>Unfortunately there don&#8217;t seem to be many PHP CircuitBreakers around &#8211; the best examples I can find (outside of what I think is proprietary code belonging to a customer) is <a title="Blog post" href="http://www.litfuel.net/plush/?postid=181">this post</a> (<a title="PHP Circuit breaker - uses MySQL" href="http://code.google.com/p/plushcode/source/browse/trunk/stability_patterns/circuit_breaker/CircuitBreaker.php">which uses a database</a>) and this<a title="ZF Circuit Breaker Proposal" href="http://artur.ejsmont.org/blog/PHP-Circuit-Breaker-initial-Zend-Framework-proposal"> proposal for one</a> to go into the Zend Framework.</p>
<p>A good circuit breaker would need to :</p>
<ul>
<li>Support multiple instances (e.g. one for Twitter, one for talking to Google or whatever)</li>
<li>Support variable timeouts and thresholds</li>
<li>Support different storage &#8216;backends&#8217; (e.g. memcache, APC, MySQL (perhaps) or fileSystem) &#8211; at which point it might be best for it to just use Zend Cache.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.palepurple.co.uk/the-circuit-breaker-design-pattern/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Help! Developer needed! (PHP/Bromsgrove) (Jan 2012)</title>
		<link>http://www.palepurple.co.uk/developer-needed-php-bromsgrove-jan-2012</link>
		<comments>http://www.palepurple.co.uk/developer-needed-php-bromsgrove-jan-2012#comments</comments>
		<pubDate>Thu, 12 Jan 2012 12:43:56 +0000</pubDate>
		<dc:creator>palepurple</dc:creator>
				<category><![CDATA[palepurple]]></category>
		<category><![CDATA[recruitment]]></category>

		<guid isPermaLink="false">http://www.palepurple.co.uk/?p=389</guid>
		<description><![CDATA[We seem to have too much work at the moment; and will need to either hire a new developer within the next few months &#8211; or use a freelancer/contractor. So if you&#8217;re looking for work (or a change) here are &#8230; <a href="http://www.palepurple.co.uk/developer-needed-php-bromsgrove-jan-2012">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>We seem to have too much work at the moment; and will need to either hire a new developer within the next few months &#8211; or use a freelancer/contractor. So if you&#8217;re looking for work (or a change) here are some details:</p>
<p>Your primary role will involve building and testing PHP based web applications.</p>
<ol>
<li>PHP &#8211; you should know about design patterns (MVC, Factory, CircuitBreaker and so on), be able to talk to a database and be aware of security considerations. You should have knowledge/experience with PHP Frameworks (e.g. Zend).</li>
<li>CSS</li>
<li>Javascript &#8211; AJAX, jQuery &#8230;</li>
<li>Unit testing &#8211; PHPUnit, Selenium and Jenkins.</li>
</ol>
<p>If anyone is interested, please contact david at palepurple.co.uk with a CV and salary expectations.</p>
<p>Please no agencies.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.palepurple.co.uk/developer-needed-php-bromsgrove-jan-2012/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple load checking shell script</title>
		<link>http://www.palepurple.co.uk/simple-load-checking-shell-script</link>
		<comments>http://www.palepurple.co.uk/simple-load-checking-shell-script#comments</comments>
		<pubDate>Thu, 24 Nov 2011 11:13:57 +0000</pubDate>
		<dc:creator>palepurple</dc:creator>
				<category><![CDATA[systems administration]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[load]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[uptime]]></category>

		<guid isPermaLink="false">http://www.palepurple.co.uk/?p=380</guid>
		<description><![CDATA[Below is a simple shell script which can be used to control execution of tasks on a Linux system based on the systems current load value &#8211; with the intention that if the 5 minute load average is greater than &#8230; <a href="http://www.palepurple.co.uk/simple-load-checking-shell-script">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Below is a simple shell script which can be used to control execution of tasks on a Linux system based on the systems current load value &#8211; with the intention that if the 5 minute load average is greater than a given value the script exits with an error return code (1) or completes without error (0).</p>
<p>In this case saved in a file called /usr/local/bin/load_check,</p>
<pre>#!/bin/bash

if [ -z $1 ]; then
    echo "Incorrect usage .... " &gt; /dev/stderr
    exit 1
fi

LOADLIMIT=$1

load_avg=$(uptime | awk -F 'load average:' '{print $2}' | cut -d, -f1)
if [[ $load_avg &lt; $LOADLIMIT ]]; then
    exit 0
fi
exit 1</pre>
<p>And usage would look like :</p>
<pre>/usr/local/bin/load_check 3 &amp;&amp; run/whatever/command</pre>
<p>It&#8217;s now possible to modify non-essential cron jobs (for example /etc/cron.d/munin) so that they do not run if the system is deemed too busy &#8211; so changing :</p>
<pre>*/5 * * * *     munin if [ -x /usr/bin/munin-cron ]; then /usr/bin/munin-cron; fi</pre>
<p>to</p>
<pre>*/5 * * * *     munin if [ -x /usr/bin/munin-cron ]; then /usr/local/bin/load_check 4 &amp;&amp; /usr/bin/munin-cron; fi</pre>
<p>Will result in munin-cron not running if the load is over 4. Rinse and repeat for other cron jobs which aren&#8217;t critical.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.palepurple.co.uk/simple-load-checking-shell-script/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gregynog 2011 &#8211; Interviewing feedback</title>
		<link>http://www.palepurple.co.uk/gregynog-2011-interviewing-feedback</link>
		<comments>http://www.palepurple.co.uk/gregynog-2011-interviewing-feedback#comments</comments>
		<pubDate>Sat, 12 Nov 2011 22:28:52 +0000</pubDate>
		<dc:creator>palepurple</dc:creator>
				<category><![CDATA[recruitment]]></category>
		<category><![CDATA[aberystwyth]]></category>
		<category><![CDATA[gregynog]]></category>
		<category><![CDATA[interviewing]]></category>
		<category><![CDATA[students]]></category>

		<guid isPermaLink="false">http://www.palepurple.co.uk/?p=368</guid>
		<description><![CDATA[Today, I interviewed a number of second year Aberystwyth Computer Science students at Gregynog. The aim of the exercise is to help prepare them for upcoming industrial placement interviews. As a whole, the students were better this year &#8211; their CVs &#8230; <a href="http://www.palepurple.co.uk/gregynog-2011-interviewing-feedback">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Today, I interviewed a number of second year <a title="Aberystywyth Computer Science" href="http://www.aber.ac.uk/compsci">Aberystwyth Computer Science</a> students at Gregynog. The aim of the exercise is to help prepare them for upcoming industrial placement interviews.</p>
<p>As a whole, the students were better this year &#8211; their CVs and covering letters had fewer obvious mistakes and appeared better prepared. The majority of students were also smartly dressed which gave a good impression.</p>
<p>However, many students undersell themselves &#8211; CVs were often missing reference to work they&#8217;d done outside their degree scheme &#8211; or the extent of the reference was &#8220;Perl&#8221; or &#8220;Python&#8221;. Yet, in one example a student had written a Python/MySQL GUI application and others had experimented with JQuery, CSS3 or HTML5.</p>
<p>Most students expressed a deep interest or passion in a specific field &#8211; yet they would often lack supporting &#8220;evidence&#8221; of self directed research. Being able to mention a mailing list / google group / relevant website / conference or hot topic within that field would lend credibility to the claim &#8211; employers want employees who are genuinely motivated and interested.</p>
<p>Finally &#8211; it was common to see students saying something like &#8220;It will help me in my degree to work for you as I&#8217;ll learn to do X and Y&#8221;. Unsurprisingly an employer is not likely to be interested in what the student will get from the employment period &#8211; they are interested in what benefits the student will bring to them and their team.</p>
<p>See also - <a title="blog post" href="http://www.palepurple.co.uk/interviewing-students-some-findings">http://www.palepurple.co.uk/interviewing-students-some-findings</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.palepurple.co.uk/gregynog-2011-interviewing-feedback/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP Barcelona conference, November 2011.</title>
		<link>http://www.palepurple.co.uk/php-barcelona-conference-november-2011</link>
		<comments>http://www.palepurple.co.uk/php-barcelona-conference-november-2011#comments</comments>
		<pubDate>Thu, 03 Nov 2011 20:48:39 +0000</pubDate>
		<dc:creator>palepurple</dc:creator>
				<category><![CDATA[conferences]]></category>
		<category><![CDATA[barcelona]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.palepurple.co.uk/?p=364</guid>
		<description><![CDATA[This is a quick summary of the PHP Barcelona conference &#8211; this is the second year one of us attended, and again it was well organised and had stimulating presentations/talks, such as: The Pomodoro Technique for time keeping Cloud hosting (managed &#8230; <a href="http://www.palepurple.co.uk/php-barcelona-conference-november-2011">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This is a quick summary of the <a title="PHP Barcelona" href="http://phpconference.es/">PHP Barcelona</a> conference &#8211; this is the second year one of us attended, and again it was well organised and had stimulating presentations/talks, such as:</p>
<ol>
<li>The <a title="Pomodoro time keeping technique" href="http://www.pomodorotechnique.com/">Pomodoro Technique</a> for time keeping</li>
<li>Cloud hosting (managed vs unmanaged with <a title="Microsoft's Azure cloud platform" href="http://www.microsoft.com/windowsazure/">Microsoft&#8217;s Azure</a>+ and <a title="Orchestra.io cloud hosting" href="http://orchestra.io/">Orchestra.io</a> as examples). This included live demos and a good coverage of the various options available (and why you might pick (for example) EC2 over Orchestra or vice versa).</li>
<li><a title="Solr Document Indexing" href="http://lucene.apache.org/solr/">Solr</a> &#8211; document indexing (which we are already using, but there was some useful content within the marathon 2 hour talk/workshop)</li>
<li>Unit testing as an afterthought &#8211; Marco Tabini (<a title="http://www.phparch.com/" href="http://www.phparch.com/">phparch.com</a>) spoke about his belief that when writing unit tests, code coverage on it&#8217;s own is not enough when it comes testing through unit tests &#8211; like phpunit &#8211; as it&#8217;s also necessary to cover how components interact with each other, and therefore effectively do testing of an entire application and not just isolated components (something we&#8217;d already discovered).</li>
<li><a title="Doctrine 2 documentation" href="http://www.doctrine-project.org/projects/orm/2.0/docs/en">Doctrine2</a> &#8211; an overview of why you should be using an ORM and not lower level SQL everywhere &#8211; followed by a quick overview of why Doctrine2 is better/faster/superior to Doctrine1.</li>
<li>PHP on the CLI &#8211; a few useful titbits where hidden within this talk covering using PHP for command line scripts (options parsing via the getopt library being the most useful).</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.palepurple.co.uk/php-barcelona-conference-november-2011/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Server resource graphing and monitoring with munin</title>
		<link>http://www.palepurple.co.uk/server-resource-graphing-and-monitoring-with-munin</link>
		<comments>http://www.palepurple.co.uk/server-resource-graphing-and-monitoring-with-munin#comments</comments>
		<pubDate>Thu, 03 Nov 2011 20:29:49 +0000</pubDate>
		<dc:creator>palepurple</dc:creator>
				<category><![CDATA[systems administration]]></category>

		<guid isPermaLink="false">http://www.palepurple.co.uk/?p=360</guid>
		<description><![CDATA[We use munin to monitor servers to help identify server performance issues (and improvements). It&#8217;s a great tool, and we keep finding the need to install it. Munin compromises two parts &#8211; firstly &#8216;munin-node&#8217; which runs as a daemon, and &#8230; <a href="http://www.palepurple.co.uk/server-resource-graphing-and-monitoring-with-munin">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>We use munin to monitor servers to help identify <a title="Linux Server Support" href="http://www.palepurple.co.uk/linux-server-support">server performance issues</a> (and improvements). It&#8217;s a great tool, and we keep finding the need to install it.</p>
<p><a title="Munin monitoring - website" href="http://munin-monitoring.org/">Munin</a> compromises two parts &#8211; firstly &#8216;munin-node&#8217; which runs as a daemon, and is responsible for running various plugin (statistics retrieval) scripts and storing the output values.  Typically plugins exist for all common services (MySQL, Apache, memcached, CPU usage etc). Secondly, a cron job processes the stored data to make pretty graphs which are accessible to the end user through a web browser. For example :</p>
<div id="attachment_362" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.palepurple.co.uk/wp-content/uploads/2011/11/Screen-shot-2011-05-31-at-00.16.47.png"><img class="size-medium wp-image-362" title="Munin graph showing MySQL Queries over time" src="http://www.palepurple.co.uk/wp-content/uploads/2011/11/Screen-shot-2011-05-31-at-00.16.47-300x207.png" alt="Munin graph showing MySQL Queries over time" width="300" height="207" /></a><p class="wp-caption-text">Munin graph showing MySQL Queries over time</p></div>
<div id="attachment_361" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.palepurple.co.uk/wp-content/uploads/2011/11/Screen-shot-2011-05-27-at-23.39.47.png"><img class="size-medium wp-image-361" title="Munin graph showing MySQL queries and throughput" src="http://www.palepurple.co.uk/wp-content/uploads/2011/11/Screen-shot-2011-05-27-at-23.39.47-300x182.png" alt="Munin graph showing MySQL queries and throughput" width="300" height="182" /></a><p class="wp-caption-text">Munin graph showing MySQL queries and throughput</p></div>
<p>In the case of the above, it&#8217;s easy to see that on around the start of Week 21 something significantly changed the amount of &#8216;work&#8217; MySQL was doing &#8211; in this case, we&#8217;d been doing some performance optimisations on <a title="Wordpress" href="http://wordpress.org">WordPress</a> and there was a significant improvement recorded. Without a long term plot of traffic, it would have been difficult for us to quantify the improvement.</p>
<p>In another scenario, we increased the amount of memory used by memcached &#8211; expecting to see a reduction in MySQL traffic (as more data ought to be cached in memory). Did it help? Not in this instance.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.palepurple.co.uk/server-resource-graphing-and-monitoring-with-munin/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Insecure PHP Code?</title>
		<link>http://www.palepurple.co.uk/insecure-php-code</link>
		<comments>http://www.palepurple.co.uk/insecure-php-code#comments</comments>
		<pubDate>Thu, 20 Oct 2011 12:40:05 +0000</pubDate>
		<dc:creator>palepurple</dc:creator>
				<category><![CDATA[training]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[phpnw]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://www.palepurple.co.uk/?p=348</guid>
		<description><![CDATA[Recently on the PHP NorthWest mailing list, there has been some discussion over the causes of security vulnerabilities within PHP applications. The original poster provided a questionnaire &#8211; however, this didn&#8217;t really allow for much in the way of a &#8230; <a href="http://www.palepurple.co.uk/insecure-php-code">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Recently on the <a href="http://groups.google.com/group/phpnw" title="PHP Northwest Mailing List">PHP NorthWest mailing list</a>, there has been some discussion over the causes of security vulnerabilities within PHP applications.</p>
<p>The original poster provided <a href="http://www.ethicalhack3r.co.uk/files/misc/questionnaire.html" title="PHP Insecurity questionnaire">a questionnaire</a> &#8211; however, this didn&#8217;t really allow for much in the way of a detailed answer, so here&#8217;s our 2 pence. As a caveat: there are obviously other causes&#8230;. :</p>
<h2>Lack of Awareness</h2>
<p>Some developers just aren&#8217;t aware of, or don&#8217;t care about, security &#8211; as a sweeping generalisation they probably won&#8217;t count themselves as a professional programmer. For example: someone who was originally a web designer and learns enough PHP to process a form and slowly moves onto bigger things. Such people are likely to be copying and pasting code which has been butchered over time to add in new fields and functionality. Their understanding of the code and language is often minimal (which is possible due to PHP&#8217;s low barrier to entry).</p>
<h2>Limited Knowledge</h2>
<p>More professional/full time developers will be aware of (for example) SQL injections &#8211; but, in some cases, only because a user had typed in &#8220;O&#8217;Reilly&#8221; or &gt; in a form and it resulted in an error occurring &#8211; and an error report being raised to them. The developer is likely to have solved the problem by littering the code-base with calls to functions like <a href="http://php.net/addslashes">addslashes()</a> or <a href="http://php.net/htmlentities">htmlentities()</a> &#8211; however, this can result in the data being encoded/escaped multiple times (so you might see &#8220;it\\\\\\\\\\\\\\&#8217;s&#8221; or &amp;ampgt;).</p>
<h2>Over-reliance on trust</h2>
<p>Other times developers may believe they can trust the end user &#8211; phases like the following are likely heard in this scenario :</p>
<ul>
<li>&#8220;They&#8217;re employees &#8211; it&#8217;s a restricted system&#8221; (e.g. accessible only on the internal network)</li>
<li>&#8220;These are non-technical users&#8221;</li>
<li>&#8220;You have to be logged in before you can view/edit any data &#8230;&#8221;</li>
</ul>
<p>Unfortunately a reliance on trust will probably lead to authentication bypass, cross site scripting and possibly data disclosure &#8211; for example, not ensuring a user is logged in before allowing for the deletion/modification of data, or not checking that someone is authorised to view an invoice before showing it. </p>
<h2>Poor application design</h2>
<p>In other circumstances, a developer will just have a horrible &#8216;foundation&#8217; to work with &#8211; whether they wrote or inherited a code-base with fundamental design issues which make it hard to develop in a secure manner going forward. As an illustration, something as simple as the following PHP code where the original author assumed the caller would always escape/sanitise/validate the inputs before using them -</p>
<p><code></p>
<pre>
function add_user($sanitised_login, $sanitised_name, $sanitised_password) {
    // probably missing length and other validity checks here.
    mysql_query("INSERT INTO users (login, name, password)
                 VALUES ('$sanitised_login', '$sanitised_name', '$sanitised_password')");
}
</pre>
<p></code></p>
<p>And at some point, the function is called and the inputs will not have been appropriately validated or sanitised &#8211; like :</p>
<pre>
<code>
add_user($_POST['x'], .....).
</code>
</pre>
<p>This is clearly a case of bad design &#8211; possibly coupled with commercial pressures which stop the developer from going back and refactoring it when the problems become apparent. </p>
<h2>Commercial Pressures</h2>
<p>It&#8217;s rare to find a customer who states security on a requirements specification. Likewise, being given the resources to perform a pro-active audit of a code-base is unlikely to gain approval from many managers when the time spent on an audit could be used to add additional functionality &#8211; which may result in a greater number of sales. Most organisations are focussed on short-term results, so refactoring a code-base, or introducing a testing suite which could take weeks or months to perform, is likely to be difficult to introduce &#8211; even with well documented long term benefits.</p>
<p>We frequently help sites to become PCI DSS compliant (which generally involves a combination of <a href="/linux-server-support" title="Systems Administration for Linux servers">systems administration</a> and <a href="/php-development-and-consultancy/security-audits" title="Security Audits/Patching for PHP Code">code review/modification</a>) &#8211; in this instance there has been a clear commercial pressure to be secure &#8211; but certainly the code review/patching part is at the wrong stage of the development cycle.</p>
<h2>The less obvious vulnerabilities</h2>
<p>There are security vulnerabilities which are harder to spot, such as session fixation, race conditions and symlink attacks.</p>
<p>Some of these are dealt with through following best practice and developer experience (for example: knowing they should not write out to a hard coded file path like /tmp/tmpfile.txt and should use <a href="http://php.net/tempnam">tempnam()</a>/<a href="http://php.net/tmpfile">tmpfile()</a> instead).</p>
<p>Others may be through use of a framework (where the framework calls session_regenerate_id() when someone authenticates, avoiding session fixation) or perhaps it passes view content through the HtmlPurifier library before it&#8217;s rendered to reduce the chance of Cross Site Scripting. Alternatively, perhaps it uses a database abstraction layer like Doctrine or Propel which makes it effectively immune to SQL injection.</p>
<p>Suffice to say, in our <a href="/php-training/security" title="PHP Security training">PHP Security training course</a> we cover various design specific items which should help the above.</p>
<h2>Everyone makes mistakes</h2>
<p>We recently <a href="/php-development-and-consultancy/security-audits" title="PHP application security auditing">reviewed a PHP app</a> written in the <a href="http://www.yiiframework.com/">Yii framework</a> (which seems to be quite a good framework). However, the developers had introduced an XSS vulnerability in a custom 404 error page they&#8217;d added &#8211; an unescaped error message was being output to the page (which contained part of the URL). </p>
<p>The Yii framework obviously contains functionality to protect an end user from such issues &#8211; for example using <code>CHtml::encode($error)</code> would have stopped <code>http://whatever/blah/&lt;img src="http://lolwut.com/layout/lolwut.jpg" alt="" /&gt;</code> from working as well.</p>
<p>Which leads into &#8230;.</p>
<h2>Detection and Risk-reduction</h2>
<p>So, although use of a framework will give a project a good foundation and hopefully reduce the scope for vulnerabilities, like everything, it is not a magic bullet and will not necessarily make the software immune to vulnerabilities. A &#8220;determined&#8221; developer can still introduce vulnerabilities. And obviously people sometimes make mistakes. </p>
<p>We didn&#8217;t realise one of our customers had an XSS vulnerability in code we&#8217;d written for them until we pointed an automated tool at the search form, and it&#8217;s for exactly this reason that we include practicals covering the use of a number of scanning tools within our <a href="/php-training/security" title="PHP Security training course">PHP security training course</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.palepurple.co.uk/insecure-php-code/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New website</title>
		<link>http://www.palepurple.co.uk/new-website</link>
		<comments>http://www.palepurple.co.uk/new-website#comments</comments>
		<pubDate>Mon, 03 Oct 2011 10:18:02 +0000</pubDate>
		<dc:creator>palepurple</dc:creator>
				<category><![CDATA[palepurple]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[website]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www4.palepurple.co.uk/?p=280</guid>
		<description><![CDATA[So, we&#8217;ve just changed our website&#8230; why? The previous website was based on Drupal, but an outdated / now unsupported version, which would at some point probably give us maintenance problems. By moving to WordPress we move to something we &#8230; <a href="http://www.palepurple.co.uk/new-website">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>So, we&#8217;ve just changed our website&#8230; why?</p>
<ol>
<li>The previous website was based on Drupal, but an outdated / now unsupported version, which would at some point probably give us maintenance problems.</li>
<li>By moving to WordPress we move to something we have more day-to-day experience with</li>
<li>The new theme has HTML5 elements within it (header, footer, article and so on) which should aid navigation and indexing.</li>
<li>The website now supports mobile devices (Android, iPhone) (screenshots below)</li>
<li>The previous site tried to display blog posts and tweets on the front page, which we thought was probably confusing &#8211; so now tweets are always in the right sidebar, and the blog now has its own distinct home.</li>
<li>The migration has resulted in us creating a new theme, which we hope is simpler to navigate and less cluttered</li>
</ol>
<div style="text-align: left;">

<a href='http://www.palepurple.co.uk/new-website/img_4342' title='Homepage on an iPhone'><img width="150" height="150" src="http://www.palepurple.co.uk/wp-content/uploads/2011/10/IMG_4342-150x150.png" class="attachment-thumbnail" alt="Screenshot of our homepage on an iPhone" title="Homepage on an iPhone" /></a>
<a href='http://www.palepurple.co.uk/new-website/img_4343' title='Screenshot of website menu on iPhone'><img width="150" height="150" src="http://www.palepurple.co.uk/wp-content/uploads/2011/10/IMG_4343-150x150.png" class="attachment-thumbnail" alt="Screenshot of website menu on iPhone" title="Screenshot of website menu on iPhone" /></a>
<a href='http://www.palepurple.co.uk/new-website/img_4344' title='Blog posts within the mobile theme'><img width="150" height="150" src="http://www.palepurple.co.uk/wp-content/uploads/2011/10/IMG_4344-150x150.png" class="attachment-thumbnail" alt="Blog posts within the mobile theme" title="Blog posts within the mobile theme" /></a>

<p>The content of the site hasn&#8217;t changed all that much &#8211; one or two pages have been dropped which weren&#8217;t really necessary, and it&#8217;s prodded us into updating some of the content (e.g. examples of our work and so on).</p>
<p>We should have the appropriate redirect rules in to stop us creating any 404 pages or harming our SEO positions.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.palepurple.co.uk/new-website/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Xerte Online Toolkits</title>
		<link>http://www.palepurple.co.uk/blog-xerte-online-toolkits</link>
		<comments>http://www.palepurple.co.uk/blog-xerte-online-toolkits#comments</comments>
		<pubDate>Wed, 28 Sep 2011 22:16:26 +0000</pubDate>
		<dc:creator>palepurple</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[xerte]]></category>

		<guid isPermaLink="false">https://office.palepurple.co.uk/steven/wp/wordpress/?p=154</guid>
		<description><![CDATA[Xerte Online Toolkits is an open source Flash+Ajax+PHP web application which allows tutors to create rich multimedia presentations through a web browser. We&#8217;ve been hosting a couple of Xerte based sites (for Techdis and Warwick University) for a couple of &#8230; <a href="http://www.palepurple.co.uk/blog-xerte-online-toolkits">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.nottingham.ac.uk/xerte/toolkits.htm">Xerte Online Toolkits</a> is an open source Flash+Ajax+PHP web application which allows tutors to create rich multimedia presentations through a web browser.</p>
<p>We&#8217;ve been hosting a couple of Xerte based sites (for <a href="http://www.techdisplayxerte.info">Techdis</a> and <a href="http://xerte.warwick.ac.uk">Warwick University</a>) for a couple of years now. Being an open source project &#8211; we initially added support to the Techdis version so that it automatically cleans itself monthly and so on (therefore creating an ideal sandpit).</p>
<p>In the past we&#8217;d encountered problems with XOT which seemed to only affect our hosting environment &#8211; and we&#8217;d spend a few hours tracking them down, patch the code and then commit our fixes to our local subversion repository and post a patch on the mailing list. A couple of weeks ago we noticed toolkits 1.7 had been released, and asked one customer if they&#8217;d like to be upgraded. Not surprisingly, they did.</p>
<p>So we set up a demo site for the 1.7 code base, using a copy of a customer&#8217;s live database &#8211; hoping it would suffice to illustrate the new code work(s) before upgrading their live version. Unfortunately it didn&#8217;t run &#8211; the database schema had significantly changed between versions &#8211; and there remains no obvious guide/help as to how to upgrade it.</p>
<p>Next up, we tried installing from scratch &#8211; but then found the various bugs we&#8217;d squashed out before had reappeared (or hadn&#8217;t been fixed in upstream).</p>
<p>At this point it became obvious that we needed to push our changes upstream to save ourselves future work.</p>
<p>So, over the last couple of days, we&#8217;ve been fairly busy, and thankfully the Xerte project have given us commit access &#8211; so hopefully our changes won&#8217;t be lost. This is just a short summary of a few changes we&#8217;ve made to the <a href="http://code.google.com/p/xerteonlinetoolkits/">Subversion trunk of toolkits</a>:</p>
<p>The existing codebase is vulnerable to SQL injection, and needs PHP&#8217;s magic_quotes functionality enabled. For various reasons (beyond the scope of this short blog post) this isn&#8217;t ideal.</p>
<p>Toolkit&#8217;s often issues database queries like the below :</p>
<p>&nbsp;</p>
<pre>include $site-&gt;php_library_path . "database_library.php";
$mysql_id=database_connect("index.php database connect success",
                                              "index.php database connect fail");
$query_response = mysql_query("SELECT x From y WHERE z = '{$_POST['template_id']}');
if($query_response === false) {
     receive_message($_SESSION['login_ldap'], "admin",
                                "critical", "something is wrong", "something is wrong");
} else {
    $row = mysql_fetch_array($query_response);
    echo $row['blahblah'];
}</pre>
<p>&nbsp;</p>
<p>Some problems with which are :</p>
<ol>
<li>Insecure &#8211; relying on magic_quotes to protect against SQL injection</li>
<li>It&#8217;s not escaping the output</li>
<li>Verbose &#8211; it&#8217;s easy enough to shrink the above into something more concise (you&#8217;ll see effectively the same 8-10 lines pasted throughout the code base with minor changes)</li>
<li>Poor error handling &#8211; what if we fail to connect to the database? What if the query string is invalid or no records are returned? Will we as developers have any way of finding out what error occurred yesterday? Or will it just silently fail for Miss O&#8217;Reilly?</li>
<li>We&#8217;re obviously tied to always using MySQL</li>
</ol>
<p>The code base also ran with PHP&#8217;s error_reporting effectively turned off &#8211; so undefined variable warnings and so on were not being reported</p>
<p>So, some fixes we&#8217;ve made are for instance :</p>
<ol>
<li>Add a db_query($sql, $params) function which performs a crude emulation of prepared statements &#8211; so providing some protection from SQL Injection. e.g.<code>$rows = db_query("select * from foo where id = ?", array($id));</code></li>
<li>Create convenience method(s) for recording debug messages (<code>_debug($string)</code>), so if something breaks some sort of audit trail exists.</li>
<li>Through the config.php file, support a &#8216;development&#8217; flag, which if enabled will set the error_reporting and _debug() function to work/do stuff</li>
<li>Create a <code>db_query_one($sql, $params)</code> function &#8211; this returns a single row or null &#8211; ideal for use if you are only expecting one row back &#8211; for example, retrieval by primary key.</li>
</ol>
<p>So the above code ends up being shrunk to :</p>
<p>&nbsp;</p>
<pre>require_once("config.php");
$row = db_query_one("SELECT x From y WHERE z = ?", array($_POST['template_id']));
if($row === null) {
     receive_message($_SESSION['login_id'], "admin",
                                "critical", "something is wrong", "something is wrong");
} else {
    echo $row['x'];
}</pre>
<p>&nbsp;</p>
<p>config.php always loads the database_library.php file, and starts a PHP session &#8211; before these were handled in a slightly haphazard manner &#8211; and in reality as it&#8217;s not possible for the someone to use the app and not require the functionality from either.</p>
<p>Other fixes/changes made include :</p>
<ol>
<li>Stopping some obvious Javascript errors from occurring with newer browsers &#8211; such as Chrome.</li>
<li>Fixing some Javascript related bugs &#8211; for example, popups being created but having empty messages</li>
<li>Merging in 5-6 patches others had contributed to the project from the Google Code bug tracker</li>
<li>Addition of some documentation covering the setup of LDAP for the application&#8217;s authentication</li>
<li>Addition of a simple logging function (_debug($string)) which should help others when installing the application in the future).</li>
<li>Re-indentation of some of the code base &#8211; so it more closely follows more popular PHP coding styles (e.g. 4 space indentation and so on).</li>
<li>Tracking down of why XOT wasn&#8217;t correctly creating a new Learning Object &#8211; this appears to have been related to a copy function which did a depth first copy (and then returned in the wrong place &#8211; so new templates were always left blank if .svn directories were present as the contents of the .svn directory would be copied, but not the &#8220;real&#8221; files.). We fixed this through refactoring to use a &#8216;cp -r&#8217; (copy_r) style function (more readable, ignores .svn directories and so on).</li>
<li>Simplification of input validation and error reporting in the login script</li>
</ol>
<p>There is plenty of work remaining to be done &#8211; for instance :</p>
<ol>
<li>Removal of all &#8216;manual&#8217; MySQL queries to be replaced with db_query*(), and therefore remove the chance of SQL injection.</li>
<li>Removal of the legacy Javascript, and changing to use something like jQuery which should provide for greater cross browser compatibility</li>
<li>Return of data to Javascript (from PHP) to be via the JSON format, rather than inline (and often) unstructured strings.</li>
<li>Adding some sort of upgrade capability (either documentation or hopefully an automated script which just &#8216;does it&#8217;</li>
</ol>
<p>Still, at least a start has been made.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.palepurple.co.uk/blog-xerte-online-toolkits/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using disk: enhanced
Object Caching 810/949 objects using disk: basic

Served from: www.palepurple.co.uk @ 2012-02-22 18:49:03 -->
