<?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>Carsonified &#187; PHP</title>
	<atom:link href="http://carsonified.com/blog/category/dev/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://carsonified.com</link>
	<description></description>
	<lastBuildDate>Tue, 16 Mar 2010 13:01:45 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>How to Debug in PHP</title>
		<link>http://carsonified.com/blog/dev/how-to-debug-in-php/</link>
		<comments>http://carsonified.com/blog/dev/how-to-debug-in-php/#comments</comments>
		<pubDate>Tue, 15 Sep 2009 07:00:31 +0000</pubDate>
		<dc:creator>Kieran Masterton</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Learn]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://carsonified.com/?p=3037</guid>
		<description><![CDATA[By <strong>Kieran Masterton</strong><br />Nobody enjoys the process of debugging their code. If you want to build killer web apps though, it&#8217;s vital that you understand the process thoroughly.
This article breaks down the fundamentals of debugging in PHP, helps you understand PHP&#8217;s error messages and introduces you to some useful tools to help make the process a little less [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fhow-to-debug-in-php%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fhow-to-debug-in-php%2F" height="61" width="51" /></a></div><p>Nobody enjoys the process of debugging their code. If you want to build killer web apps though, it&#8217;s vital that you understand the process thoroughly.</p>
<p>This article breaks down the fundamentals of debugging in PHP, helps you understand PHP&#8217;s error messages and introduces you to some useful tools to help make the process a little less painful.</p>
<p><em>Editor&#8217;s Note: We&#8217;ll be running workshops like &#8220;How to Build a Web App from A-Z&#8221; at <a href="http://events.carsonified.com/fowa/2009/london/workshops#workshop_53?utm_source=TV&#038;utm_medium=Text%2Blink&#038;utm_campaign=How%2Bto%20Debug%20in%20PHP">The Future of Web Apps London</a>.</em></p>
<p><span id="more-3037"></span></p>
<h3>Doing your Ground Work</h3>
<p>It is important that you configure PHP correctly and write your code in such a way that it produces meaningful errors at the right time. For example, it is generally good practice to turn on a verbose level of error reporting on your development platform. This probably isn&#8217;t such a great idea, however, on your production server(s). In a live environment you neither want to confuse a genuine user or give malicious users too much information about the inner-workings of your site.</p>
<p>So, with that in mind lets talk about the all too common &#8220;I&#8217;m getting no error message&#8221; issue. This is normally caused by a syntax error on a platform where the developer has not done their ground work properly. First, you should turn display_errors on. This can be done either in your php.ini file or at the head of your code like this:</p>
<p><code>&lt;?php<br />
ini_set('display_errors', 'On');</code></p>
<p><em>Tip: In these code examples I omit the closing (?&gt;) PHP tag. It is <a href="http://framework.zend.com/manual/en/coding-standard.php-file-formatting.html#coding-standard.php-file-formatting.general" title="Zend Coding Standards">generally considered good practice</a> to do so in files which contain only PHP code in order to avoid accidental injection of white space and the all too common &#8220;headers already sent&#8221; error.</em></p>
<p>Next, you will need to set an error reporting level. As default PHP 4 and 5 do not show PHP notices which can be important in debugging your code (more on that shortly). Notices are generated by PHP whether they are displayed or not, so deploying code with twenty notices being generated has an impact upon the overhead of your site. So, to ensure notices are displayed, set your error reporting level either in your php.ini or amend your runtime code to look like this:</p>
<p><code>&lt;?php<br />
ini_set('display_errors', 'On');<br />
error_reporting(E_ALL);</code></p>
<p><em>Tip: E_ALL is a constant so don&#8217;t make the mistake of enclosing it in quotation marks.</em></p>
<p>With PHP 5 it&#8217;s also a good idea to turn on the E_STRICT level of error reporting. E_STRICT is useful for ensuring you&#8217;re coding using the best possible standards. For example E_STRICT helps by warning you that you&#8217;re using a deprecated function. Here&#8217;s how to enable it at runtime:</p>
<p><code>&lt;?php<br />
ini_set('display_errors', 'On');<br />
error_reporting(E_ALL | E_STRICT);</code></p>
<p>It is also worth mentioning that on your development platform it is often a good idea to make these changes in your php.ini file rather than at the runtime. This is because if you experience a syntax error with these options set in your code and not in the php.ini you may, depending on your set up, be presented with a blank page. Likewise, it is worth noting that if you&#8217;re setting these values in your code, a conditional statement might be a good idea to avoid these settings accidentally being deployed to a live environment.</p>
<h3>What Type of Error am I Looking at?</h3>
<p>As with most languages, PHP&#8217;s errors may appear somewhat esoteric, but there are in fact only four key types of error that you need to remember:</p>
<p><strong>1. Syntax Errors</strong></p>
<p>Syntactical errors or parse errors are generally caused by a typo in your code. For example a missing semicolon, quotation mark, brace or parentheses. When you encounter a syntax error you will receive an error similar to this:</p>
<p><code><strong>Parse error:</strong> syntax error, unexpected T_ECHO in /Document/Root/example.php on line 6</code></p>
<p>In this instance it is important that you check the line above the line quoted in the error (in this case line 5) because while PHP has encountered something unexpected on line 6, it is common that it is a typo on the line above causing the error. Here&#8217;s an example:</p>
<p><code>&lt;?php<br />
ini_set('display_errors', 'On');<br />
error_reporting(E_ALL);<br/><br/><br />
$sSiteName = "Think Vitamin"<br />
echo $sSiteName;</code></p>
<p>In this example I have omitted the semi-colon from line 5, however, PHP has reported an error occurred on line 6. Looking one line above you can spot and rectify the problem.</p>
<p><em>Tip: In this example I am using <a href="http://en.wikipedia.org/wiki/Hungarian_notation" title="Wikipedia entry for Hungarian Notation">Hungarian Notation</a>. Adopting this coding standard can aid with debugging code while working collaboratively or on a piece of code you wrote some time ago. The leading letter denoting the variable type means that determining a variable type is very quick and simple. This can aid in spotting irregularities which can also help highlight any potential logic errors.</em></p>
<p><strong>2. Warnings</strong></p>
<p>Warnings aren&#8217;t deal breakers like syntax errors. PHP can cope with a warning, however, it knows that you probably made a mistake somewhere and is notifying you about it. Warnings often appear for the following reasons:</p>
<ol>
<li>Headers already sent. Try checking for white space at the head of your code or in files you&#8217;re including.</li>
<li>You&#8217;re passing an incorrect number of parameters to a function.</li>
<li>Incorrect path names when including files.</li>
</ol>
<p><strong>3. Notices</strong></p>
<p>Notices aren&#8217;t going to halt the execution of your code either, but they can be very important in tracking down a pesky bug. Often you&#8217;ll find that code that&#8217;s working perfectly happily in a production environment starts throwing out notices when you set error_reporting to E_ALL.</p>
<p>A common notice you&#8217;ll encounter during development is:</p>
<p><code>><strong>Notice:</strong> Undefined index: FullName in /Document/Root/views/userdetails.phtml on line 55</code></p>
<p>This information can be extremely useful in debugging your application. Say you&#8217;ve done a simple database query and pulled a row of user data from a table. For presentation in your view you&#8217;ve assigned the details to an array called $aUserDetails. However, when you echo $aUserDetails['FirstName'] on line 55 there&#8217;s no output and PHP throws the notice above. In this instance the notice you receive can really help.</p>
<p>PHP has helpfully told us that the FirstName key is undefined so we know that this isn&#8217;t a case of the database record being NULL. However, perhaps we should check our SQL statement to ensure we&#8217;ve actually retrieved the user&#8217;s first name from the database. In this case the notice has helped us rule out a potential issue which has in turn steered us towards the likely source of our problem. Without the notice our likely first stop would have been the database record, followed by tracing back through our logic to eventually find our omission in the SQL.</p>
<p><strong>4. Fatal Errors</strong></p>
<p>Fatal Errors sound the most painful of the four but are in fact often the easiest to resolve. What it means, in short, is that PHP understands what you&#8217;ve asked it to do but can&#8217;t carry out the request. Your syntax is correct, you&#8217;re speaking its language but PHP doesn&#8217;t have what it needs to comply. The most common fatal error is an undefined class or function and the error generated normally points straight to the root of the problem:</p>
<p><code><strong>Fatal error:</strong> Call to undefined function create() in /Document/Root/example.php on line 23</code></p>
<h3>Using var_dump() to Aid Your Debugging</h3>
<p>var_dump() is a native PHP function which displays structured, humanly readable, information about one (or more) expressions. This is particularly useful when dealing with arrays and objects as var_dump() displays their structure recursively giving you the best possible picture of what&#8217;s going on. Here&#8217;s an example of how to use var_dump() in context:</p>
<p>Below I have created an array of scores achieved by users but one value in my array is subtly distinct from the others, var_dump() can help us discover that distinction.</p>
<pre><code>&lt;?php
ini_set('display_errors', 'On');
error_reporting(E_ALL);<br/><br/>
$aUserScores = array('Ben' => 7,'Linda' => 4,'Tony' => 5,'Alice' => '9');
echo '&lt;pre&gt;';
var_dump($aUserScores);
echo '&lt;/pre&gt;';</code></pre>
<p><em>Tip: Wrap var_dump() in &lt;pre&gt; tags to aid readability.</em></p>
<p>The output from var_dump() will look like this:</p>
<pre><code>array(4) {
  ["Ben"]=>
  int(7)
  ["Linda"]=>
  int(4)
  ["Tony"]=>
  int(5)
  ["Alice"]=>
  string(1) "9"
}</code></pre>
<p>As you can see var_dump tells us that $aUserScores is an array with four key/value pairs. Ben, Linda, and Tony all have their values (or scores) stored as integers. However, Alice is showing up as a string of one character in length.</p>
<p>If we return to my code, we can see that I have mistakenly wrapped Alice&#8217;s score of 9 in quotation marks causing PHP to interpret it as a string. Now, this mistake won&#8217;t have a massively adverse effect, however, it does demonstrate the power of var_dump() in helping us get better visibility of our arrays and objects.</p>
<p>While this is a very basic example of how var_dump() functions it can similarly be used to inspect large multi-dimensional arrays or objects. It is particularly useful in discovering if you have the correct data returned from a database query or when exploring a JSON response from say, Twitter:</p>
<p><code>&lt;?php<br />
ini_set('display_errors', 'On');<br />
error_reporting(E_ALL);<br/><br/><br />
$sJsonUrl = 'http://search.twitter.com/trends.json';<br/><br/><br />
$sJson = file_get_contents($sJsonUrl,0,NULL,NULL);<br />
$oTrends = json_decode($sJson);<br/><br/><br />
echo '&lt;pre&gt;';<br />
var_dump($oTrends);<br />
echo '&lt;/pre&gt;';</code></p>
<h3>Useful Tools to Consider when Debugging</h3>
<p>Finally, I want to point out a couple of useful tools that I&#8217;ve used to help me in the debugging process. I won&#8217;t go into detail about installing and configuring these extensions and add-ons, but I wanted to mention them because they can really make our lives easier.</p>
<p><strong>Xdebug</strong></p>
<p><a href="http://www.xdebug.org/" title="Xdebug">Xdebug</a> is a PHP extension that aims to lend a helping hand in the process of debugging your applications. Xdebug offers features like:</p>
<ul>
<li>Automatic stack trace upon error</li>
<li>Function call logging</li>
<li>Display features such as enhanced var_dump() output and code coverage information.</li>
</ul>
<p>Xdebug is highly configurable, and adaptable to a variety of situations. For example, stack traces (which are extremely useful for monitoring what your application is doing and when) can be configured to four different levels of detail. This means that you can adjust the sensitivity of Xdebug&#8217;s output helping you to get granular information about your app&#8217;s activity.</p>
<p>Stack traces show you where errors occur, allow you to trace function calls and detail the originating line numbers of these events. All of which is fantastic information for debugging your code.</p>
<p><em>Tip: As default Xdebug limits var_dump() output to three levels of recursion. You may want to change this in your xdebug.ini file by setting the xdebug.var_display_max_depth to equal a number that makes sense for your needs.</em></p>
<p>Check out <a href="http://www.xdebug.org/docs/install" title="Xdebug installation guide">Xdebug&#8217;s installation guide</a> to get started.</p>
<p><strong>FirePHP</strong></p>
<p>For all you <a href="https://addons.mozilla.org/en-US/firefox/addon/1843" title="FireBug">FireBug</a> fans out there, <a href="http://www.firephp.org/" title="FirePHP">FirePHP</a> is a really useful little PHP library and Firefox add-on that can really help with AJAX development.</p>
<p>Essentially FirePHP enables you to log debug information to the Firebug console using a simple method call like so:</p>
<p><code>&lt;?php<br />
	$sSql = 'SELECT * FROM tbl';<br />
	FB::log('SQL query: ' . $sSql);</code> </p>
<p>In an instance where I&#8217;m making an AJAX search request, for example, it might be useful to pass back the SQL string my code is constructing in order that I can ensure my code is behaving correctly. All data logged to the Firebug console is sent via response headers and therefore doesn&#8217;t effect the page being rendered by the browser.</p>
<p><em>Warning: As with all debug information, this kind of data shouldn&#8217;t be for public consumption. The downside of having to add the FirePHP method calls into your PHP is that before you go live you will either have to strip all these calls out or set up an environment based conditional statement which establishes whether or not to include the debug code.</em></p>
<p>You can install the Firefox add-on at <a href="http://www.firephp.org/" title="FirePHP">FirePHP&#8217;s website</a> and also <a href="http://www.firephp.org/HQ/" title="Fire PHP libs">grab the PHP libs</a> there too. Oh, and don&#8217;t forget if you haven&#8217;t already installed FireBug, <a href="https://addons.mozilla.org/en-US/firefox/addon/1843" title="FireBug">you&#8217;ll need that too</a>.</p>
<h3>In Conclusion &#8230;</h3>
<p>Hopefully during the course of this article you have learned how to do your ground work by preparing PHP for the debugging process; recognise and deal with the four key PHP error types and use var_dump() to your advantage. Likewise, I hope that you will find Xdebug and FirePHP useful and that they will make your life easier during your development cycle. </p>
<p>As I&#8217;ve already mentioned, and I really can&#8217;t say this enough, always remember to remove or suppress your debug output when you put your sites into production after all there&#8217;s nothing worse than all your users being able to read about your errors in excruciating detail.</p>
<p>Got a great debugging tip to share? Do you use a great little PHP extension that makes your bug trapping life easier? Please tell us about them in comments below!</p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=3037&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/dev/how-to-debug-in-php/feed/</wfw:commentRss>
		<slash:comments>58</slash:comments>
		</item>
		<item>
		<title>Tip for Streamlining Your PHP if(statements)</title>
		<link>http://carsonified.com/blog/dev/php/tip-for-streamlining-your-php-ifstatements/</link>
		<comments>http://carsonified.com/blog/dev/php/tip-for-streamlining-your-php-ifstatements/#comments</comments>
		<pubDate>Wed, 05 Aug 2009 15:01:23 +0000</pubDate>
		<dc:creator>Keir Whitaker</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://carsonified.com/?p=2608</guid>
		<description><![CDATA[By <strong>Keir Whitaker</strong><br />Recently I have been working on a WordPress plugin for Think Vitamin which necessitated getting back into the swing of PHP.
Whilst getting my head around how to create the plugin I started to delve into some of the core WordPress files and came across an unfamiliar yet syntactically sweet PHP control structure. It&#8217;s a simple [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fphp%2Ftip-for-streamlining-your-php-ifstatements%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fphp%2Ftip-for-streamlining-your-php-ifstatements%2F" height="61" width="51" /></a></div><p>Recently I have been working on a WordPress plugin for Think Vitamin which necessitated getting back into the swing of PHP.</p>
<p>Whilst getting my head around how to create the plugin I started to delve into some of the core WordPress files and came across an unfamiliar yet syntactically sweet PHP control structure. It&#8217;s a simple if statement used in a file that combines PHP and HTML.</p>
<p><span id="more-2608"></span></p>
<p><strong>Old version:</strong></p>
<p><code>&lt;?php if(&lt;your evaluation here&gt;) { ?&gt;<br />
// Output<br />
&lt;?php } else { ?&gt;<br />
// Output<br />
&lt;?php }; ?&gt;</code></p>
<p><strong>New version: Much easier to read</strong></p>
<p><code>&lt;?php if(&lt;your evaluation here&gt;): ?&gt;<br />
// Output<br />
&lt;?php else: ?&gt;<br />
// Output<br />
&lt;?php endif; ?&gt;</code></p>
<p>It also works on &#8220;for&#8221; and &#8220;while&#8221; loops as well as &#8220;elseif&#8221;.</p>
<p>I have never been a fan of combining HTML and PHP, preferring the separation of code and HTML offered by template engines like Smarty, but I could be persuaded. To me this is syntactically much clearer and in my opinion wouldn&#8217;t be too difficult for non &#8220;coders&#8221; working on your project to grasp.</p>
<p>Here are two further examples from WordPress:</p>
<p><code>&lt;?php if (have_posts()) : while (have_posts()) : the_post(); ?&gt;</code></p>
<p><code>&lt;?php if (have_posts()) : while (have_posts()) : the_post(); ?&gt;<br />
// Output<br />
&lt;?php endwhile; else: ?&gt;<br />
// Output<br />
&lt;?php endif; ?&gt;</code></p>
<p>There are always new things to learn and learning from other people&#8217;s code is a great place to start.</p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=2608&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/dev/php/tip-for-streamlining-your-php-ifstatements/feed/</wfw:commentRss>
		<slash:comments>41</slash:comments>
		</item>
		<item>
		<title>Handy Tips from Tipster</title>
		<link>http://carsonified.com/blog/carsonified/features/handy-tips-to-help-you-out/</link>
		<comments>http://carsonified.com/blog/carsonified/features/handy-tips-to-help-you-out/#comments</comments>
		<pubDate>Fri, 01 May 2009 12:03:29 +0000</pubDate>
		<dc:creator>Ryan Carson</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[Geolocation]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://thinkvitamin.com/?p=1286</guid>
		<description><![CDATA[By <strong>Ryan Carson</strong><br />There have been a ton of helpful and interesting tips posted to Tipster recently, so I thought we&#8217;d pull a few out for you all (and give the submitters a bit of well-deserved publicity).
Topics that we&#8217;re covering are: MySQL, CSS, JavaScript, PHP, JQuery, life hacks and server admin.
MySQL Geo Search
Here&#8217;s a MySQL statement to search [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fcarsonified%2Ffeatures%2Fhandy-tips-to-help-you-out%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fcarsonified%2Ffeatures%2Fhandy-tips-to-help-you-out%2F" height="61" width="51" /></a></div><p>There have been a ton of helpful and interesting tips posted to <a href="http://tipster.carsonified.com">Tipster</a> recently, so I thought we&#8217;d pull a few out for you all (and give the submitters a bit of well-deserved publicity).</p>
<p>Topics that we&#8217;re covering are: MySQL, CSS, JavaScript, PHP, JQuery, life hacks and server admin.</p>
<h3><a href="http://tipster.carsonified.com/categories/web-apps/mysql-geo-search/">MySQL Geo Search</a></h3>
<p>Here&#8217;s a MySQL statement to search for nearest objects to you in a database, &#8216;lat&#8217; &amp; &#8216;lng&#8217; are fields in the &#8216;items&#8217; table with the location of object and $latitude &amp; $longitude are the users location. The distance field will be the calculated distance in Km between the user and the object:</p>
<p><code>SELECT *,(((acos(sin((&quot;.$latitude.&quot;*pi()/180)) * sin((`lat`*pi()/180))+cos((&quot;.$latitude.&quot;*pi()/180)) * cos((`lat`*pi()/180)) * cos(((&quot;.$longitude.&quot;- `lng`)*pi()/180))))*180/pi())*60*1.1515*1.609344) as distance FROM `items` ORDER BY distance;<!--formatted--></code></p>
<p>By: <a href="http://mogotion.com/">Sam Machin</a><br />
<a href="http://tipster.carsonified.com/categories/web-apps/mysql-geo-search/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/css/transparent-background-images-png-fix-for-ie6-a-fe/">Transparent background images &#8211; PNG fix for IE6 &#8211; a few reminders</a></h3>
<p>When using the MS filter (via The AlphaImageLoader) to fix PNG transparency for IE6 — in your CSS, remember to:</p>
<ol>
<li>Set width and height for the element/s containing the transparent background image.</li>
<li>First set background to none — then apply filter for background image.</li>
<li>Apply &#8216;position: relative;&#8217; to any contained links to ensure functionality</li>
</ol>
<p>(Also, bear in mind that the background images can no longer be tiled or positioned via &#8216;background-position&#8217;).</p>
<p>By: <a href="http://eyelearn.org/">Prisca</a><br />
<a href="http://tipster.carsonified.com/categories/css/transparent-background-images-png-fix-for-ie6-a-fe/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/javascript/address-longitude-and-latitude-in-google-maps/">Address Longitude and Latitude in Google Maps</a></h3>
<p>Google maps does not show the Longitude and Latitude of an address you search. To get this information, enter this piece of JavaScript into you browsers address bar and hit enter:</p>
<p><code>javascript:void(prompt(&#39;&#39;,gApplication.getMap().getCenter()));<!--formatted--></code></p>
<p>A little window will then pop-up displaying the Longitude and Latitude for you. Bingo!</p>
<p>[Editor's note: If you add this to your bookmarks toolbar, it's even easier to use. Just click it whenever you're on Google Maps. Hat tip to <a href="http://kyanmedia.com">Phil Balchin</a>.]</p>
<p>By: <a href="http://www.twitter.com/zoltarSpeaks">Pete Roome</a><br />
<a href="http://tipster.carsonified.com/categories/javascript/address-longitude-and-latitude-in-google-maps/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/php/custom-details-in-code-hints-zend-studio-for-eclip/">Custom Details in Code Hints &#8211; Zend Studio for Eclipse</a></h3>
<p>Zend Studio is a brilliant platform for PHP development. In my view, well worth the cost. One of the best things about it now being built on Eclipse is the project-wide code hinting.</p>
<p>When you see the built-in code hints and highlight an option, you get loads of lovely details regarding the functions and classes that you are about to use&#8230; as you would expect from most modern IDEs. However, Zend Studio for Eclipse takes this further for your own classes and functions!</p>
<p>When you have written your classes and functions, start placing a multi-line comment just above the opening line, i.e. /**, hit Return and Studio will prompt you for data types and descriptions for your method variables.</p>
<p>This is invaluable in understanding those classes you wrote at 3:47am, 3.5 years ago and haven&#8217;t used since!</p>
<p>By: <a href="http://flipstorm.co.uk/">Simon Hamp</a><br />
<a href="http://tipster.carsonified.com/categories/php/custom-details-in-code-hints-zend-studio-for-eclip/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/css/use-a-print-stylesheet/">Use a Print Stylesheet</a></h3>
<p>Print stylesheets allow you to change the style of your page when printing, without having to provide a separate &#8220;print version&#8221; of the markup.</p>
<p>You specify a print CSS by adding &#8220;media=&#8217;print&#8217;&#8221; as an attribute to the link tag.</p>
<p><code>&lt;link rel="stylesheet" type="text/css" media="print" href="print.css"/&gt;<!--formatted--></code></p>
<p>In the print CSS you should remove unnecessary elements such as sidebars, menus, background colours, presentational images, etc so as not to waste ink and paper on parts which don&#8217;t need to be printed. You can also change the font and size to make sure the text is clear on the printed page.</p>
<p>You can even add some CSS to show the URLs of links on the page, which wouldn&#8217;t normally be seen when printing.</p>
<p><code>a[href]:after { content: &quot; (&quot; attr(href) &quot;) &quot;; }<!--formatted--></code></p>
<p>By: <a href="http://wblinks.com/">Rich Adams</a><br />
<a href="http://tipster.carsonified.com/categories/css/use-a-print-stylesheet/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/css/make-your-links-easier-to-read/">Make your links easier to read</a></h3>
<p>Instead of using { text-decoration: underline; } on your links (as browsers do by default) use:</p>
<p><code>{ border-bottom: 1px solid; }.</code></p>
<p>This makes your links easier to read, as there will be more space between the text and the line underneath, so the line will no longer cross through your &#8216;y&#8217;s and &#8216;g&#8217;s.</p>
<p>You can also then style your underline with all the usual border stylings, much more exciting than a plain underline :)</p>
<p>By: <a href="http://laurakalbag.com/">Laura Kalbag</a><br />
<a href="http://tipster.carsonified.com/categories/css/make-your-links-easier-to-read/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/jquery/manual-filmstrips-in-jquery">Manual filmstrips in jQuery</a></h3>
<p>Really simple manual photo film-strip in jQuery. Used to swap a large image on a page with that of a thumbnail elsewhere on the page, such as different photos of a product in an e-commerce store.</p>
<p><code><br />
$(document).ready(function(){<br />
imageSwapper(&quot;.thumbnails a&quot;);<br />
});<br />
<!--formatted--></code></p>
<p><code><br />
function imageSwapper(link) {<br />
$(link).click(function(){<br />
$(&amp;#039;#largeimage&amp;#039;).attr(&amp;#039;src&amp;#039;, this.href);<br />
return false;<br />
});<br />
};<br />
<!--formatted--></code></p>
<p>Just link the thumbnails to their larger versions and pop them in a div or paragraph of class thumbnails, and give the large image an ID of large image, and you are good to go!</p>
<p>By: <a href="http://www.michaelpeacock.co.uk/">Michael Peacock</a><br />
<a href="http://tipster.carsonified.com/categories/jquery/manual-filmstrips-in-jquery">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/web-apps/store-user-passwords-as-salted-hashes/">Store user passwords as salted hashes</a></h3>
<p>Just using a hash of the user password is not strong enough. If two users have the same password, they&#8217;ll have the same hash. Dictionary attacks are also still possible as the attacker can have a list of dictionary word hashes. Using a salted hash involves generating a random string of characters, which you then concatenate with the password before hashing. Two users with the same password will then have different hashes, and the stored hash will never just be a hash of a common word if the user chose a weak password. You then store the salt, and the hashed value in your database.</p>
<p><code>hash_to_store = sha1(salt + real_pass)</code></p>
<p>There are many different methods you could use too, such as concatenating the salt with a hash of the password and then hashing that, etc.</p>
<p><code>hash_to_store = sha1(sha1(real_pass) + ...</code></p>
<p>By: <a href="http://wblinks.com/">Rich Adams</a><br />
<a href="http://tipster.carsonified.com/categories/web-apps/store-user-passwords-as-salted-hashes/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/life-hacks/cddvd-stuck-in-macbook/">CD/DVD stuck in Macbook</a></h3>
<p>Having gotten a DVD stuck inside my Macbook the other day, i found the only way to force eject it was to hold down the trackpad button on reboot. DVD popped right out.</p>
<p>By: <a href="http://www.twitter.com/zoltarSpeaks">Pete Roome</a><br />
<a href="http://tipster.carsonified.com/categories/life-hacks/cddvd-stuck-in-macbook/">Vote on this tip</a></p>
<p>Photo credit: <a href="http://www.flickr.com/photos/mance">flickr.com/photos/mance</a></p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=1286&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/carsonified/features/handy-tips-to-help-you-out/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>Silverlight for PHP Developers</title>
		<link>http://carsonified.com/blog/carsonified/features/silverlight-for-php-developers/</link>
		<comments>http://carsonified.com/blog/carsonified/features/silverlight-for-php-developers/#comments</comments>
		<pubDate>Fri, 13 Mar 2009 15:00:16 +0000</pubDate>
		<dc:creator>Mark Quirk</dc:creator>
				<category><![CDATA[Browsers]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[microsoft]]></category>
		<category><![CDATA[Silverlight]]></category>

		<guid isPermaLink="false">http://thinkvitamin.com/?p=974</guid>
		<description><![CDATA[By <strong>Mark Quirk</strong><br />A Microsoft browser plug-in might seem an odd target for the PHP developer, more used to working with open source platforms such as Linux, Apache and the MySQL database server. However there is much about Microsoft Silverlight that makes it a good match to such technologies. For a start, it is a free download and [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fcarsonified%2Ffeatures%2Fsilverlight-for-php-developers%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fcarsonified%2Ffeatures%2Fsilverlight-for-php-developers%2F" height="61" width="51" /></a></div><p>A Microsoft browser plug-in might seem an odd target for the PHP developer, more used to working with open source platforms such as Linux, Apache and the MySQL database server. However there is much about <a href="http://silverlight.net/">Microsoft Silverlight</a> that makes it a good match to such technologies. For a start, it is a free download and there are versions that run not only on Microsoft Windows XP and Vista but also on Intel-based Apple Macs running OS X 10. It is designed to work not only with Microsoft Internet Explorer but with all major Web browsers, and Microsoft is taking particular care to ensure compatibility with Firefox and Safari. There is even a version for Linux called Moonlight which is being developed as part of the open source Mono Project.</p>
<p>Silverlight is a powerful tool for creating Internet applications that go considerably beyond the capabilities of standard HTML and CSS. It supports a wide range of visual effects and has more than 30 user interface controls built-in, including not only buttons, list boxes and sliders but also a data grid and a calendar. It can display PNG and JPEG image files, and play back WMV, WMA and MP3 media with support for 720p HDTV display modes. Silverlight 1.0 was released in April 2007. The current version is Silverlight 2.0 (originally referred to as Silverlight 1.1) which is fully compatible with the original while offering many enhancements.</p>
<p><strong>Inside a Silverlight application</strong><br />
You define the application that you want Silverlight to present using XAML (eXtensible Application Markup Language). This is based on the XML specification and was designed by Microsoft for initialising structured values and objects. The following XAML document declares a Canvas object containing a TextBlock, which is a lightweight element for displaying text:</p>
<p><img src="http://img.skitch.com/20090316-xse1yrc13d6e36e36y3u9qeei6.png" alt="Code example. Click link below to donwload actual text."></p>
<p><a href="http://thinkvitamin.com/wp-content/uploads/2009/01/silverlight-code.zip">Download complete code example</a></p>
<p>The visual elements that make up a Silverlight application need to be placed within a container object, and this provides a reference in which they can be positioned. In our example we are using a Canvas object measuring 300 by 100 pixels as the container and we have set its Background property so that it displays in a light blue color. Into this we have placed a single TextBlock object which will display the traditional ‘Hello World!’ text string in a Verdana font 30 pixels in size and 10 pixels below and to the right of the top-left corner of the Canvas object. Note the dot syntax that we have employed to reference properties of the Canvas object.</p>
<p>Actually displaying a Silverlight application within an HTML page need involve little more than a standard Object tag. At its simplest, the following renders our example within a browser:</p>
<p><img src="http://img.skitch.com/20090316-j3piqiwe4gyqjy6dptm64y64k1.png" alt="Code example. Click link below to donwload actual text."></p>
<p><a href="http://thinkvitamin.com/wp-content/uploads/2009/01/silverlight-code.zip">Download complete code example</a></p>
<p>Here we have defined a space 300 pixels wide and 100 pixels wide in which to place the Silverlight plug-in, as defined by its MIME type. We have also defined a data attribute for the plug-in. In practice this is usually ignored but it can boost performance with some browsers (and note that the trailing comma is necessary as the attribute takes two parameters, the second having a ‘null’ value in this case). Finally, in the event that the client does not have Silverlight 2.0 installed, the anchor element displays a ‘Get Silverlight’ image from the Microsoft Web site which is linked to the page from which the user can download and install the plug-in.</p>
<p>The Silverlight plug-in takes a number of parameters but in this context the most important is ‘source’ which tells the plug-in where to find the application. In this case we are directing it to the file ‘silverlightapp.xml’. If this was to contain the XAML of our earlier example in simple text form, and both these files were uploaded to a directory on your Web server, then opening the HTML page would result in our ‘Hello World!’ application appearing to the top-left of your browser.</p>
<p>The XAML that defines the Silverlight application need not reside in a separate file. It can instead be defined within the page that instantiates the plug-in using a special script block. For example, we could insert the following immediately before the ‘pluginHost’ div block in our HTML page above, which also shows off some of the special effects supported by Silverlight:</p>
<p><img src="http://img.skitch.com/20090316-1d6e137qymm1th7b2d3h234m6n.png" alt="Code example. Click link below to donwload actual text."></p>
<p><a href="http://thinkvitamin.com/wp-content/uploads/2009/01/silverlight-code.zip">Download complete code example</a></p>
<p>We reference this XAML block by changing the ‘source’ parameter for the Silverlight1 object as follows:</p>
<p><img src="http://img.skitch.com/20090316-btpmx13k73gxmk79g7tfrmsiep.png" alt="Code example. Click link below to donwload actual text."></p>
<p><a href="http://thinkvitamin.com/wp-content/uploads/2009/01/silverlight-code.zip">Download complete code example</a></p>
<p>The hash character indicates that what follows references a script block on the current page. The other principle difference between this and our earlier XAML example is that we have placed a Rectangle object on the Canvas. This is a Shape element, as is the Line, Ellipse, Polygon and Polyline, and as such supports a wider range of display options. The RadiusX and RadiusY attributes round the corners of the Rectangle, while the Fill property allows us to specify a Brush object. In this case we have used the LinearGradientBrush to shade the Rectangle in a graduated blend of yellow and light blue.</p>
<p>Most of the other parameters supported by the Silverlight plug-in can be ignored at this stage. However ‘minRuntimeVersion’ can be useful if you want to ensure, for example, that version 2.0 is installed rather than version 1.0. This can be accompanied by ‘autoUpgrade’ which means that an attempt should be made to upgrade automatically in the event of too early a version being found. There is also the ‘OnLoad’ parameter which can specify a JavaScript function that should be run once the plug-in is loaded (more on that later).</p>
<p>If you want to know more about the options available when instantiating Silverlight, then the article ‘Instantiating a Silverlight Plug-in’ from Microsoft’s MSDN Library is a good place to start.</p>
<p><strong>Using PHP with Silverlight</strong><br />
For the PHP developer, the important point is that the source for the Silverlight object can be anything that returns XAML, and that includes a PHP script. This opens up many possibilities. For example, the following PHP page uses Silverlight to display data extracted from a MySQL database:</p>
<p><img src="http://img.skitch.com/20090316-cmbi1kr98aatyr7sya9378x2k6.png" alt="Code example. Click link below to donwload actual text."></p>
<p><a href="http://thinkvitamin.com/wp-content/uploads/2009/01/silverlight-code.zip">Download complete code example</a></p>
<p>Assuming this is part of the page ‘customers.php’ on our PHP server, then calling it with the following URL would cause Silverlight to display the name, city and postcode of the 134th customer in the database:</p>
<p>http://myserver.com/customers.php?ID=134</p>
<p>Having extracted the ID value from the query string, the code opens a connection to the database and then runs a query which gets the data for the customer specified and places it in the object $result. The function mysqli_fetch_array() extracts the data from $result into the array $row, from where it can be read and inserted into the XAML using the echo command.<br />
This is far from production code, with little in the way of error checking, but it does serve to demonstrate how PHP can be used to generate a Silverlight application. For the sake of simplicity our example embeds the XAML within the page that instantiates the Silverlight control, but you could equally specify a PHP page as the source for the Silverlight control itself, as in the following snippet:</p>
<p><img src="http://img.skitch.com/20090316-xmwm5x3pqk67k11mpaty7fibx5.png" alt="Code example. Click link below to donwload actual text."></p>
<p><a href="http://thinkvitamin.com/wp-content/uploads/2009/01/silverlight-code.zip">Download complete code example</a></p>
<p>All that is required here is that the page clients.php return valid XAML code that can be rendered by Silverlight.</p>
<p><strong>Adding user interaction with JavaScript</strong><br />
The Silverlight plug-in exposes a JavaScript API that allows any XAML element can be manipulated by JavaScript, in much the same way that you would program against the HTML Document Object Model (DOM) exposed by the page. Furthermore, Silverlight boasts a wide range of programmable events which opens up many possibilities for user interaction.</p>
<p>For example, in the following we have added an ‘x:Name’ attribute to the TextBlock element. This allows JavaScript to access and manipulate the element using the findName function. We have also attached an event handler stating that the JavaScript function changeText should be executed if the user depresses the left mouse button while the pointer is over the Canvas element:</p>
<p><img src="http://img.skitch.com/20090316-d4mf3ka6yd56ei2yq41g9rhyub.png" alt="Code example. Click link below to donwload actual text."></p>
<p><a href="http://thinkvitamin.com/wp-content/uploads/2009/01/silverlight-code.zip">Download complete code example</a></p>
<p>We can now define the changeText function by adding the following to the page that instantiates the Silverlight object:</p>
<p><img src="http://img.skitch.com/20090316-11nsrcpdrh4mdtatje4w2t9964.png" alt="Code example. Click link below to donwload actual text."></p>
<p><a href="http://thinkvitamin.com/wp-content/uploads/2009/01/silverlight-code.zip">Download complete code example</a></p>
<p>This script locates the element we want to manipulate using the findName function, and then sets its Text attribute to change from ‘Hello World!’ to ‘Goodbye!’ when the Canvas is clicked. One important point to note here is that the JavaScript is interpreted by the browser and not by the Silverlight plug-in. The x:Name attribute provides a handle that allows the findName function to reach into Silverlight for objects declared within the XAML code.</p>
<p>You can use these techniques to respond to a wide range of events. The API allows you to respond to simple movements of the mouse, or when the mouse pointer enters or leaves an object. You can respond to the depression of the left mouse button, and when it is released. Most objects respond to key up and key down events as well, and there are facilities for determining the key combination. The TextBox control supports a TextChanged event, while the PasswordBox control supports a PasswordChanged event and the Button control supports a Click event</p>
<p>One of Silverlight’s great strengths is this ability to manipulate anything you declare in your XAML code through a coherent object model. Check out the Silverlight Developer Center in the MSDN Library for a comprehensive reference to the whole API.</p>
<p><strong>Interacting with a PHP Web Service</strong><br />
Most of the techniques discussed so far work with both versions of Silverlight. However Silverlight 2.0 opens up new possibilities for client-side processing as it includes a version of the .NET Framework and the Common Language Runtime (CLR) which allows it to run client-side code written in C#, Visual Basic and many other languages. The code for such programs is compressed into a single ZIP file together with the XAML definition and a manifest (also written in XML). The result is given the file extension XAP and referenced through the plug-in’s source parameter in the same way as we referenced our XAML file in the example above. When the page containing the plug-in is opened by the client, the XAP file is downloaded and unpacked, and then the code is compiled and executed.</p>
<p>This opens up further opportunities for the PHP programmer as such applications can make calls to Web services, and those Web services can be defined in PHP. For such an application to work the service has to be SOAP 1.1 compliant, and you will need to define a clientaccesspolicy.xml file if the service comes from a different domain to the application. This is to prevent cross-site forgery (see the article Making a Service Available Across Domain Boundaries for more on this).</p>
<p>It is also worth noting that Silverlight 2.0 also includes the Dynamic Language Runtime (DLR) which supports IronPython, IronRuby and Managed JScript. These languages are being developed at Microsoft’s open source project hosting site Codeplex. For further details see Silverlight Dynamic Languages SDK.</p>
<p><strong>Choosing the Right Tools</strong><br />
While not a requirement, Microsoft has released a number of tools that would be useful to the PHP developer looking to work with Silverlight. Microsoft Visual Web Developer 2008 Express Edition is a useful Web page designer with full support for CSS, JavaScript and AJAX. It can also be used with Silverlight Tools for Visual Studio 2008 to automate production of much of the infrastructure behind a Silverlight application. Both can be downloaded from the Microsoft Web site free of charge.</p>
<p>Microsoft Expression Blend 2 is a professional graphic design tool that outputs XAML, allowing designers to create attractive user interfaces and to automatically generate the code required by Silverlight for its display. Alternatively increased support from the community means there are a growing number of third party XAML editors out there as well.</p>
<p>Sitting alongside Blend 2 is Microsoft Expression Web 2. Aimed at the professional Web designer, this latest release introducing many features that have been designed specifically for the PHP developer. There are menu options for inserting common PHP snippets, including pre-defined form, URL and session variables, server side includes and other structures. Furthermore, Expression Web 2 will render the page in Design View as though all the code, including server side includes, were in a single file, allowing you to see your code in action without leaving the editor.</p>
<p>Expression Web 2 understands PHP which means it will colour code language constructs intelligently, and there is full support for auto-completion so that you can see what functions and parameters are available to you as you write the code. Expression Web 2 also includes the PHP 5.2.5 runtime which you can use locally as a development server.</p>
<p>So Silverlight has a great deal to offer the PHP developer &#8211; something that Microsoft is clearly recognising with its support for PHP in Expression Web 2. Trial versions of Microsoft’s Expression range are available for download.</p>
<p>[Main image by Pathfinder Linden]</p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=974&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/carsonified/features/silverlight-for-php-developers/feed/</wfw:commentRss>
		<slash:comments>49</slash:comments>
		</item>
		<item>
		<title>How to Create an RSS-Enabled, Micro-Blog with Twitter</title>
		<link>http://carsonified.com/blog/web-apps/how-to-create-an-rss-enabled-micro-blog-with-twitter/</link>
		<comments>http://carsonified.com/blog/web-apps/how-to-create-an-rss-enabled-micro-blog-with-twitter/#comments</comments>
		<pubDate>Tue, 20 Jan 2009 19:59:33 +0000</pubDate>
		<dc:creator>Ryan Carson</dc:creator>
				<category><![CDATA[Features]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Social Media]]></category>
		<category><![CDATA[Web Apps]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[news feed]]></category>
		<category><![CDATA[RSS]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://thinkvitamin.com/?p=780</guid>
		<description><![CDATA[By <strong>Ryan Carson</strong><br />Have you ever wanted to create a simple multi-person blog, but didn&#8217;t want to bother setting up an entire WordPress installation? If so then we&#8217;ve got just the answer. By combining Twitter Search, Atom feeds, hash-tags and PHP, you can create an RSS-enabled, micro-blog using Twitter and be up and running in less than 10 [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fweb-apps%2Fhow-to-create-an-rss-enabled-micro-blog-with-twitter%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fweb-apps%2Fhow-to-create-an-rss-enabled-micro-blog-with-twitter%2F" height="61" width="51" /></a></div><p>Have you ever wanted to create a simple multi-person blog, but didn&#8217;t want to bother setting up an entire WordPress installation? If so then we&#8217;ve got just the answer. By combining <a href="http://search.twitter.com">Twitter Search</a>, Atom feeds, hash-tags and PHP, you can create an RSS-enabled, micro-blog using Twitter and be up and running in less than 10 minutes.</p>
<p>The new <a href="http://feeds.feedburner.com/vnews">Think Vitamin news feed</a> is powered this way, so let me show you how we built it.</p>
<div class="wp-caption alignnone" style="width: 333px"><img title="Screenshot of a micro-blog" src="http://img.skitch.com/20090119-nwfaked8h5c71db9ns32dptkfp.png" alt="" width="323" height="262" /><p class="wp-caption-text">Screenshot of the Think Vitamin news feed</p></div>
<p><strong>Sign up for Twitter</strong></p>
<p>First off, make sure you and the other blog contributors have <a href="http://twitter.com">Twitter</a> accounts. It&#8217;s free and only takes two minutes to sign up.</p>
<p><strong>Choose your Hash-Tag</strong></p>
<p>The way you will post to the blog is by including a &#8216;hash-tag&#8217; in your Twitter post. For example, we chose <a href="http://search.twitter.com/search?q=%23thinkvitamin">#thinkvitamin</a> for the news feed. It can be anything, but make sure it&#8217;s not too common so you don&#8217;t pull in Tweets that are irrelevant (ie #strawberries or #obama). A great way to check is to search for potential hash-tags at <a href="http://search.twitter.com">search.twitter.com</a> and see how many times they&#8217;re used. The fewer the better.</p>
<p><strong>Create Your Atom Feed</strong></p>
<p>Head over to <a href="http://search.twitter.com">search.twitter.com</a> and type the following into the search bar:</p>
<p><code>#your-hash-tag from:user01 OR from:user02 OR from:user03</code></p>
<p>Replace &#8216;your-hash-tag&#8217; with the hash-tag you&#8217;ve chosen, and &#8216;user01&#8242;, &#8216;user02&#8242; and &#8216;user03&#8242; with the Twitter usernames of the folks who have permission to contribute to the blog. You can include as many Twitter usernames as you like.</p>
<p>This will return results from user01 or user02 or user03 where the hash-tag &#8216;#your-hash-tag&#8217; was used. Now copy the &#8216;Feed for this query&#8217; link to your clipboard (you&#8217;ll need it later).</p>
<p><a href="http://img.skitch.com/20090119-x6naumbyeueikstqkkkkwjwfgm.png"><img class="alignnone" title="Feed Query screenshoot" src="http://img.skitch.com/20090119-fpqegsdxst2j2eajysm8dsrct6.png" alt="" width="400" height="230" /></a></p>
<p><strong>Output the Atom Feed as HTML</strong></p>
<p>You can use PHP (or any language of your choice) to parse the feed and output it to a page as HTML. This is where you&#8217;ll need the feed URL you copied in the last step.</p>
<p>The file atom-html.php (<a href="http://carsonified.com/wp-content/uploads/2009/01/atom-html.zip">download the source</a>) outputs certain nodes of the Atom feed as list items in an unordered list. You can then style this list however you like. Here is an example of how to implement the code:</p>
<p><code><br />
&lt;ul&gt;<br />
&lt;?php<br />
include('atom-html.php');</code></p>
<p># The URL for the Atom feed from search.twitter.com<br />
$url = &#8220;http://search.twitter.com/search.atom?q=<br />
%23your-hash-tag+from%3Auser01+OR+from%3Auser02+OR+from%3Auser03&#8243;;</p>
<p># Create object to hold data and display output<br />
$atom_parser = new myAtomParser($url);</p>
<p># Return string containing HTML. The argument for getOutput() is the<br />
# number of items to display<br />
$output = $atom_parser-&gt;getOutput(5);<br />
echo $output;<br />
?&gt;<br />
&lt;/ul&gt;</p>
<p><strong>Count the Subscribers with FeedBurner</strong></p>
<p>It&#8217;s important to know how many subscribers you have, so make sure to pipe the Atom feed (that you created in the &#8216;Create Your Atom Feed&#8217; above) through <a href="http://feedburner.com">FeedBurner</a>. If you don&#8217;t have an account, it&#8217;s free and easy to sign up.</p>
<p>Once you have a URL from FeedBurner for your feed, make sure to include it as the &#8216;Subscribe&#8217; link in the HTML.</p>
<p><strong>What About Comments?</strong></p>
<p>We haven&#8217;t enabled any commenting on the Think Vitamin news feed, but this could be added by including a <a href="http://disqus.com">Disqus</a> snippet in the HTML output.</p>
<p><strong>That&#8217;s it.</strong></p>
<p>We told you it was easy. Let us know if you&#8217;re currently using Twitter on any of your sites in an interesting way.</p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=780&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/web-apps/how-to-create-an-rss-enabled-micro-blog-with-twitter/feed/</wfw:commentRss>
		<slash:comments>322</slash:comments>
		</item>
		<item>
		<title>Give your web app international appeal with PHP, Part II</title>
		<link>http://carsonified.com/blog/dev/give-your-web-app-international-appeal-part-ii/</link>
		<comments>http://carsonified.com/blog/dev/give-your-web-app-international-appeal-part-ii/#comments</comments>
		<pubDate>Tue, 19 Jun 2007 08:00:19 +0000</pubDate>
		<dc:creator>Steve Ellis</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Business]]></category>

		<guid isPermaLink="false">http://www.thinkvitamin.com/features/webapps/give-your-web-app-international-appeal-part-ii</guid>
		<description><![CDATA[By <strong>Steve Ellis</strong><br />In part one we covered the basics of how to get your website internationalised. In this part we&#39;re going to take things a stage further and look at some of the real world problems you might encounter when working with other languages.
Plurals
Dealing with plurals is the first challenge when internationalising a website.  Let&#39;s imagine [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fgive-your-web-app-international-appeal-part-ii%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fgive-your-web-app-international-appeal-part-ii%2F" height="61" width="51" /></a></div><p>In <a href="http://www.thinkvitamin.com/features/webapps/give-your-web-app-international-appeal" target="_blank">part one</a> we covered the basics of how to get your website internationalised. In this part we&#39;re going to take things a stage further and look at some of the real world problems you might encounter when working with other languages.</p>
<h3>Plurals</h3>
<p>Dealing with plurals is the first challenge when internationalising a website.  Let&#39;s imagine you&#39;re building a blogging engine and want a simple label at the bottom of each post to say how many comments have been posted. You could begin by creating two entries in the PO file; one for &#39;comment&#39; and one for &#39;comments&#39;, then choosing one based on how many comments there are. The problem with this approach is you are assuming there are only ever two types of plural (which there are in English). This is not always the case with other languages.</p>
<p>Eastern European languages for example quite often have three plural forms, some Asian languages such as Japanese don&#39;t even use plural forms. The <a href="http://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html" target="_blank">plural forms</a> section of the gettext manual has the following example of how they work in Polish when describing a number of files (plik):</p>
<p>1 plik<br />
2,3,4 pliki<br />
5-21 pliko&#39;w<br />
22-24 pliki<br />
25-31 pliko&#39;w
</p>
<p>As you can see it has 3 different types of plurals (plik, pliki, pliko&#39;w), other issues arise in languages, like Spanish, where other words change depending on plurality, for example:</p>
<p>the red car<br />
<em>el coche rojo</em></p>
<p>the red cars<br />
<em>los coches rojos</em></p>
<p>In this case just altering the Spanish word for car (coche) wouldn&#39;t be enough since the article and adjective need to be changed as well.</p>
<p>So how do we compensate for this? It turns out <code>gettext</code> already has a way of dealing with this using the function <code>ngettext</code> over <code>gettext</code> in places where we need to use plurals. It works the same as <code>gettext</code> but takes two extra parameters: the first is the sentence in it&#39;s plural form and the second is the number relating to the plural, so this might be the number of comments or in this case the number of cars.</p>
<p>Our PHP will look like this:</p>
<pre>
<code>
  //Old singular form
  echo gettext("the red car");

  //New plural form
  echo ngettext("the red car", "the red cars", $numberOfCars);
</code>
</pre>
<p>When we generate our PO file using <code>xgettext</code> it will see that we&#39;ve used <code>ngettext</code> and generate a place for our translator to type in the singular and plural forms of the whole sentence, like so:</p>
<pre>
<code>
  msgid "the red car"
  msgid_plural "the red cars"
  msgstr[0] "el coche rojo"
  msgstr[1] "los coches rojos"
</code>
</pre>
<p>The number in square brackets indicates the type of plural, so for Polish we would have:</p>
<pre>
<code>
  msgid "file"
  msgid_plural "files"
  msgstr[0] "plik"
  msgstr[1] "pliki"
  msgstr[2] "pliko&#39;w"
</code>
</pre>
<p>But if we wanted to print &#39;42 files&#39; how would <code>gettext</code> know which of the three plurals to pick? We have to tell it through a formula. Somewhere near the top of your PO file (you may need to open it in a plain text editor for this) you need to add something similar to the following to describe your language. In this example we&#39;ll just use English:</p>
<pre>
<code>
  "Plural-Forms: nplurals=2; plural=n != 1;n"
</code>
</pre>
<p>So what on earth does that mean? Well <code>nplurals</code> tells gettext how many plurals the language has (English has two), <code>plural</code> then defines the formula where <code>n</code> is the number passed to ngettext via the third parameter. In this case if <code>n == 1</code> then <code>plural</code> will equal 0 (i.e. not a plural) otherwise it will equal 1 (i.e. use the plural). Thankfully we can reuse this for languages such as German, Spanish, Italian and Dutch. For other languages such as Polish and Czech the formula becomes a bit more complicated:</p>
<pre>
<code>
  Plural-Forms: nplurals=3;
                plural=n==1 ? 0 :
                n>=2 &#038;&#038; n<=4 &#038;&#038; (n0<10 || n0>=20) ? 1 : 2; //Polish

  Plural-Forms: nplurals=3;
		plural=(n==1) ? 0 : (n>=2 &#038;&#038; n<=4) ? 1 : 2;  //Czech
</code>
</pre>
<p>Fortunately the plurals section of the gettext manual has a <a href="http://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html" target="_blank">list</a> (they start about half way down) of most of the formulas you&#39;re ever likely to need, so you can just copy and paste them into your PO file header. This saves much banging of your head against the wall whilst trying to work out terrifying formulas for languages like Russian:</p>
<pre>
<code>
  Plural-Forms: nplurals=3;
		plural=n==1 &#038;&#038; n0!=11 ? 0 :
	        n>=2 &#038;&#038; n<=4 &#038;&#038; (n0<10 || n0>=20) ? 1 : 2;
</code>
</pre>
<p>Yikes!</p>
<h3>Dynamic Data</h3>
<p>One of the problems mentioned briefly in part one was dynamic data. For example: what if you want to place a user&#39;s name into a sentence: &#8220;John likes apples&#8221;. This could be approached like this:</p>
<pre>
<code>
  echo $name . " " . gettext("likes apples");
</code>
</pre>
<p>What happens when our new language needs to put something in front of the name? For example in Spanish this sentence would be:</p>
<p><em>A John le gustan las manzanas</em></p>
<p>An &#39;a&#39; has been added to the start of the sentence. It&#39;s not optional and we need a way to allow our translator to add it. The simplest approach to this is to use something like <a href="http://www.php.net/sprintf" target="_blank"><code>sprintf</code></a> e.g.</p>
<pre>
<code>
  echo gettext("%s likes apples");
</code>
</pre>
<p>Our translator can then provide the following translation in the PO file:</p>
<pre>
<code>
  msgid "%s likes apples"
  msgstr "A %s le gustan las manzanas"
</code>
</pre>
<p>Our PHP then becomes:</p>
<pre>
<code>
  echo sprintf(gettext("%s likes apples"), $name);
</code>
</pre>
<p><code>Sprintf</code> also allows for numbered arguments which means the translator can swap their order if they need to, numbered arguments can look at bit confusing to non-techies so you could write your own version of <code>sprintf</code> that uses a simpler numbered syntax, on Diarised this is exactly what we did which means instead of seeing something like <code>%2\$s</code>, our translators see <code>{2}</code>.</p>
<p>While <code>sprintf</code> is good for situations like the one above it&#39;s not so great for links. At present you may need to stick something like this in your PO file:</p>
<pre>
<code>
  msgid &#39;<a href="<a href="http://www.example.com" target="_blank">www.example.com</a>&#8220;>click here</a> to visit our home page&#39;
</code>
</pre>
<p>Just as we didn&#39;t want to give our translator PHP code we shouldn&#39;t be giving it HTML either. While we could break it down and add entries for both &#39;click here&#39; and &#39;to go to our home page&#39; this isn&#39;t a very good solution since your translator will almost certainly need to see the whole sentence in context in order to produce an accurate translation.</p>
<p>For Diarised we wrote a <code>sprintf</code> style function to look for square brackets and turn the text inside them into links e.g.:</p>
<pre>
<code>
  echo linkprintf("[click here] to visit our home page", "<a href="http://www.example.com" target="_blank">www.example.com</a>&#8220;);
</code>
</pre>
<p>This means we can hide HTML from our translator and also keep the urls out of the translation file, so our translator sees:</p>
<pre>
<code>
  msgid &#39;[click here] to visit our home page&#39;
  msgstr &#39;[haz clic aquÃ­] para visitar nuestra pÃ¡gina de inicio
</code>
</pre>
<h3>Localising other content</h3>
<p>As we&#39;ve seen <code>gettext</code> is great for localising text but what about things like images, videos and audio? For Diarised we needed localised images for our Diary graphic on the home page as well as for some of the buttons. We approached this by writing a function that emulated gettext but would return localised files if available, dropping back to English by default.</p>
<pre>
<code>
  function get_localised_resource(<wbr>$localePath, $normalPath, $filename){
    $locale = $_SESSION[&#8221;locale&#8221;];    //get the current locale
    $localePath = &#8220;locale/$localePath/$filename&#8221;;    //path to localised resource
    if(file_exists($localePath)){    //if our localised version exists, return it
      return $localePath;
    }else{
      $normalPath = $normalPath.&#8221;/&#8221;.$filename;    //if not check for our fallback version
      if(file_exits($normalPath)){    //if it exists, return it
        return $normalPath;
      }else{
	return null;    //otherwise return null
      }
    }
  }

  function get_localised_image($filename){
    return get_localised_resource(&#8221;images<wbr>&#8220;, &#8220;templates/_img&#8221;, $filename);
  }
</code>
</pre>
<p>Here we have a generic localised function that checks for a localised resource and an example of the kind of function you could write to use it. The first parameter we pass (&#8221;images&#8221;) tells our function which folder our localised content is in, so if our locale is Spanish our path will be locale/es_ES/images/.</p>
<p>Our second parameter is where to look if it can&#39;t find the localised version, we keep our regular images in a folder called templates but you&#39;ll obviously need to update this for your own projects. This means we can put something like this into our HTML:</p>
<pre>
<code>
  <img src="<?php echo get_localised_image("welcome.jpg")?>&#8220;>
</code>
</pre>
<p>From this point adding &#8212; for example &#8212; localised video is just a case of creating a new function get_localised_video that just passes different directory names to our main <code>get_localised_resource</code> function.  For Diarised we even went as far doing this for our e-mails. Although, since these are text, we could have used <code>gettext</code> it&#39;s always neater to keep content like e-mails separate from code and this allowed us to do it.</p>
<h3>Automatically setting the locale</h3>
<p>A nice touch for a localised website is to try and work out what language the user might want the website to appear in. Although there&#39;s no way of knowing for certain we can make an educated guess that will probably get it right for most of your visitors. The way to do this is by checking the language header sent by the user&#39;s browser when it requests a page. For example mine looks like this:</p>
<pre>
<code>
  en-gb,en-us;q=0.7,en;q=0.3
</code>
</pre>
<p>This lists the three preferred languages, en-gb (British English), en-us (US English), en (English), the last two are followed by <code>q=</code> and a number indicating the quality value, the higher this value the more the user prefers it. If the figure is missed (such as with en-gb) it uses the default value of 1. Lets look at another example:</p>
<pre>
<code>
  es-es,de;q=0.7,en;q=0.3
</code>
</pre>
<p>This particular user is saying, send me Spanish if you&#39;ve got it, if not German and if you haven&#39;t got that then English, so with this in mind how can we go about sending a page in the user&#39;s preferred language if it&#39;s available? In PHP you can check the user&#39;s preferred language by calling <code>$_SERVER["HTTP_ACCEPT_LANGUAGE<wbr>&#8220;]</code>. From there you can write a function that uses regular expressions to work out the user&#39;s preferred language or if you&#39;re feeling lazy you can just use the one we wrote for Diarised:</p>
<pre>
<code>
  function get_accept_language(){
    $matches = preg_split("/,[ ]?/", $_SERVER["HTTP_ACCEPT_LANGUAGE<wbr>&#8220;]);
    $results = array();
    foreach($matches as $match){
      if(preg_match(&#8221;/;q=(d[.d] )<wbr>/&#8221;, $match, $scoreArr)){
        $score = $scoreArr[1];
      }else{
        $score = 1;
      }
      $results[$score] = str_replace($scoreArr[0], &#8220;&#8221;, $match);
    }
    krsort($results);
    return $results;
}
</code>
</pre>
<p>This will return the languages codes in an array sorted in the order the users wants, this allows you to search through the array until you find a language you support. It&#39;s worth remembering you should only do this as a last resort when you don&#39;t know for certain which language your user wants. So if they&#39;ve chosen to see the website in French don&#39;t force it to appear in German just because their browser says is German their preferred language.</p>
<h3>Conclusion</h3>
<p>That&#39;s it. hopefully with the help of these articles you&#39;ll be able to start producing your own  internationalised websites. We&#39;ve covered a lot but actually this is just the tip of the iceberg. Other issues include formatting dates, times, numbers, names and telephone numbers. There are also region specific things even between countries that speak the same language for example the US has zip codes while in the UK we have post-codes. I&#39;ll leave you to figure out some of this for yourselves!</p>
<p>If you&#39;d like to learn more about this the <a href="http://www.w3.org/International/" target="_blank">internationalisation</a> section of the w3c website is a great start. They have lots of useful information on things such as <a href="http://www.w3.org/International/questions/qa-date-format" target="_blank">date formats</a>, <a href="http://www.w3.org/International/questions/qa-forms-utf-8" target="_blank">forms</a> and <a href="http://www.w3.org/International/tutorials/tutorial-char-enc" target="_blank">character sets</a> as well as a nice list of <a href="http://www.w3.org/International/quicktips/" target="_blank">tips</a> that cover most of the issues you might run into. I&#39;d also highly recommend reading <a href="http://www.joelonsoftware.com/articles/Unicode.html" target="_blank">The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)</a> from Joel on Software, character encoding issues can be a complete nightmare so it&#39;s well worth trying to understand how they work so you can avoid them.</p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=1746&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/dev/give-your-web-app-international-appeal-part-ii/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Give your web app international appeal with PHP, Part I</title>
		<link>http://carsonified.com/blog/dev/give-your-web-app-international-appeal/</link>
		<comments>http://carsonified.com/blog/dev/give-your-web-app-international-appeal/#comments</comments>
		<pubDate>Mon, 04 Jun 2007 08:00:32 +0000</pubDate>
		<dc:creator>Steve Ellis</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Business]]></category>

		<guid isPermaLink="false">http://www.thinkvitamin.com/features/webapps/give-your-web-app-international-appeal</guid>
		<description><![CDATA[By <strong>Steve Ellis</strong><br />Building web apps can be a lot of fun &#8211; particularly if people like and use them. If you dig through your stats the chances are that people from all over the world are visiting you and they speak lots of different  languages. By only serving your app or website in English you&#8217;re assuming [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fgive-your-web-app-international-appeal%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fgive-your-web-app-international-appeal%2F" height="61" width="51" /></a></div><p>Building web apps can be a lot of fun &#8211; particularly if people like and use them. If you dig through your stats the chances are that people from all over the world are visiting you and they speak lots of different  languages. By only serving your app or website in English you&#8217;re assuming that everyone can speak it, or at least understand it well enough to get by. Just as learning to speak a new language can open the door to new cultures and ways of thinking, having a website that speaks multiple languages allows you to engage people who might otherwise have left looking for an alternative.</p>
<p>This was the situation we found ourselves in back in March just after we launched <a href="http://www.diarised.com">Diarised</a>. We had people not only visiting us from all over the world but blogging about us in many different languages. We thought it would be a nice idea to get Diarised working in a few.</p>
<p>The process of getting your website ready for multiple languages is known as internationalisation. Internationalisation goes beyond getting the website working in other languages and covers aspects such as dates, times and currency. In this two part article we&#8217;re going to look at how you go about preparing a website for internationalisation. Then we&#8217;ll look at solutions to some of the real-world problems that can arise, such as dynamic data and plurals.</p>
<h3>Associative Arrays</h3>
<p>As a first stab at internationalisation we might try using associative arrays. We could store our translated text using the English text as the key, like so:</p>
<pre>
<code>
  //set up our language arrays

  $english["welcome to example.com"] = "welcome to example.com";
  $english["have a nice day"] = "have a nice day";

  $spanish["welcome to example.com"] = "Bienvenidos a example.com";
  $spanish["have a nice day"] = "Ten un d&iacute;a bueno";
  ...

  /*
  *  We'll set the locale based on a variable in the query string
  */

  switch($_GET["lang"]){
    case "es":		            //es turns the page into Spanish
      $messages = $spanish;
      break;

    default:			    //everything else defaults back to English
      $messages = $english;
      break;
  }
  ...

  echo $messages["welcome to example.com"]
</code>
</pre>
<p>Adding new languages should then be a case of adding more arrays and updating the switch statement. Perfect! Well not quite. There are a few issues with this approach:</p>
<ol>
<li>Dynamic data. What if you need to insert someone&#8217;s username into a sentence? Breaking the sentence down into lots of little phrases will only make your translator&#8217;s life difficult and will probably lead to inaccurate translations.</li>
<li>You&#8217;re assuming your translator will be able to understand PHP array syntax and avoid breaking everything. What happens when they decide to stick something in quotation marks? The last thing you want to do after receiving a translation is to start debugging syntax errors.</li>
<li>This approach won&#8217;t fail gracefully. What happens if you accidentally type: <code>echo $messages["wlcome to example.com"]</code> By missing off the &#8220;e&#8221; your translation will break and leave blank text.</li>
</ol>
<p>Clearly this method has issues. What we really want is a way to allow non-techies to translate our text for us and a way for us to simply &#8220;plug&#8221; the translation back into the website.</p>
<h3>Introducing Gettext</h3>
<p>After ruling out associative arrays to do Diarised translation&#8217;s we decided to use <a href="http://www.gnu.org/software/gettext/">gettext</a>. gettext is the GNU internationalization library and it provides an excellent way of separating code from content. If you&#8217;re hosting on Linux there&#8217;s a good chance it will already be installed on your server.</p>
<h4>So, how does it work?</h4>
<p>The official Gettext website gives a highly detailed and fairly confusing <a href="http://www.gnu.org/software/gettext/manual/gettext.html#Overview">overview</a> but the gist is:</p>
<ol>
<li>You pass every piece of text you need translated through a function called gettext</li>
<li>Once everything has been marked up you run the xgettext command to create a PO (Portable Object) file. This is a plain text file containing the source text and a place for the translated text</li>
<li>You send this to your translator to open with a PO editor</li>
<li>Once your translator has filled out the translations they send the PO file back to you</li>
<li>You compile the PO file into a MO (Machine Object) file that gettext can read</li>
<li>You set the locale of your site to a language (usually through the query string) and sit back and admire your website in a totally different language</li>
</ol>
<p>Step 1 is just a case of the following:</p>
<pre>
<code>
  &lt;p&gt;welcome to example.com&lt;/p&gt;
</code>
</pre>
<p>becomes</p>
<pre>
<code>
  &lt;p&gt;&lt;? echo gettext("welcome to example.com"); ?&gt;&lt;/p&gt;
</code>
</pre>
<p>Marking up your code to use gettext is probably the most irritating step but fortunately you only have to do this once. It will then work for as many languages as you like. The next stage is to get this information into our translation file.</p>
<h3>How to create a PO file</h3>
<p>The first step is to set up the directory structure:</p>
<ol>
<li>In your webroot folder create a folder called locale</li>
<li>Inside that create a folder for each language you plan on supporting and use the language code as the folder name, e.g. for Spanish use es_ES or if you wanted say a localised Argentine version you could have es_AR</li>
<li>Inside each of those folders create a new one called LC_MESSAGES. This is where we will keep our translation files</li>
</ol>
<p>To create the PO file you&#8217;ll need to use the command line but don&#8217;t worry we&#8217;re here to hold your hand. Fire up a terminal window, connect to your webserver and be brave.<br /> The command we need is called xgettext, this will scan a script looking for calls to gettext then grab the text you&#8217;re passing and put it into a PO file. For example:</p>
<pre>
<code>
  # xgettext -o messages.po *.php
</code>
</pre>
<p>This will search every PHP page in the current working directory and stick the results in messages.po.  Once this is done open the file with a plain text editor and make the following change:</p>
<pre>
<code>
  "Content-Type: text/plain; charset=CHARSETn"
</code>
</pre>
<p>becomes</p>
<pre>
<code>
  "Content-Type: text/plain; charset=utf-8n"
</code>
</pre>
<p>Now save it and send it to your translator</p>
<p>Although a PO file is a plain text file its contents aren&#8217;t particularly friendly. Luckily there are a few pieces of software that make editing PO files a bit easier (especially for your translator). For Windows there&#8217;s <a href="http://www.poedit.net/">poedit</a>, and for the Mac there&#8217;s <a href="http://www.triplespin.com/en/products/locfactoryeditor.html">LocFactory Editor</a>. Both are free and will make your translators lives much easier.</p>
<p>When your translator sends the PO file back stick it into the appropriate LC_MESSAGES folder created earlier and open a terminal window so we can compile it</p>
<p>In your command window go to the LC_MESSAGES folder with messages.po and issue the following:</p>
<pre>
<code>
  # msgfmt messages.po
</code>
</pre>
<p>Assuming there were no errors this will churn out a file called messages.mo. This is the compiled file gettext will actually read, any changes to your PO file will require you to redo this step to make the changes live. Now all we need to do is tell gettext which language we want our text in.</p>
<h3>Binding a locale</h3>
<p>This step can be done via a few lines of PHP near the start of your script:</p>
<pre>
<code>
  $locale = $_GET["locale"];

  putenv("LC_ALL=$locale");
  setlocale(LC_ALL, $locale);

  bindtextdomain("messages", "locale/");	//binds the messages domain to the locale folder
  bind_textdomain_codeset("messages","UTF-8"); 	//ensures text returned is utf-8, quite often this is iso-8859-1 by default
  textdomain("messages");	//sets the domain name, this means gettext will be looking for a file called messages.mo
</code>
</pre>
<p><code>$locale</code> will need to be set to the locale that you want the website appear in. To begin with it&#8217;s simplest to set this via the query string as shown above. One of the advantages of gettext is that if it can&#8217;t find a folder for the locale you pick it will just go back to English, meaning when someone sticks locale=kl expecting a Klingon version they&#8217;ll just get English.</p>
<p>That&#8217;s it for part one. At this point you should be able to at least make a start on preparing your websites for internationalisation. In part two we&#8217;re going to look at some of the real world issues you&#8217;re likely to run into and tell you what we did to solve them on Diarised.</p>
<p><script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=1744&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/dev/give-your-web-app-international-appeal/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
