<?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>Aviblock.com &#187; php</title>
	<atom:link href="http://www.aviblock.com/blog/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.aviblock.com/blog</link>
	<description>My musings on web development</description>
	<lastBuildDate>Thu, 03 Jun 2010 13:40:47 +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>Review of the Apostrophe CMS for symfony</title>
		<link>http://www.aviblock.com/blog/2010/04/21/review-of-the-apostrophe-cms-for-symfony/</link>
		<comments>http://www.aviblock.com/blog/2010/04/21/review-of-the-apostrophe-cms-for-symfony/#comments</comments>
		<pubDate>Thu, 22 Apr 2010 02:15:30 +0000</pubDate>
		<dc:creator>Avi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[apostrophe]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.aviblock.com/blog/?p=95</guid>
		<description><![CDATA[I know I gave my blessing before to diem, and I&#8217;ll still admit that it is a very good CMS. However, it has always bothered me a little bit just how invasive this CMS is. While it bills itself as a symfony plugin, it is in truth anything but. You must start out using diem, [...]]]></description>
			<content:encoded><![CDATA[<p>I know I gave my blessing before to diem, and I&#8217;ll still admit that it is a very good CMS. However, it has always bothered me a little bit just how invasive this CMS is. While it bills itself as a symfony plugin, it is in truth anything but. You must start out using diem, and then add a little symfony in when you need it.<br />
I was reading, recently, a <a href="http://www.sympalphp.org/blog/the-status-of-sympal-a-call-to-the-community">post</a> on the sympal blog. In this post, Ryan Weaver echoed my latent feelings that a CMS should <em>empower</em> your site with CMS capabilities, but should not take it over completely. In other words, the perfect medium would be in the form of a plugin for symfony 1.x, or bundle perhaps for Symfony 2.x.<br />
There was a <a href="http://www.sympalphp.org/blog/the-status-of-sympal-a-call-to-the-community#comment_39">comment</a> put in there by somebody from the apostrophe team, which made me realize that, apostrophe was perhaps already meeting this goal. Seeing as I needed to pick a new CMS for an upcoming project, I thought I&#8217;d take it for a spin.<span id="more-95"></span><br />
I&#8217;ll start with, what is in my opinion, the basic backbone of what any CMS should be able to do.</p>
<ol>
<li>The first thing, I believe, is managing your websites structure and hierarchy of pages. I don&#8217;t consider this to be the same thing as content, but it is certainly fundamental to a website. Even if your site contains some applications (a blog, a wiki, etc.), there should be a way of shoving them under this rubric, as well.
</li>
<li>The next thing, of course, is managing content. Its not called a <strong>content managment</strong> system for naught, after all. Unfortunately, content is a very overloaded term. Most CMS&#8217;s seem to connect that to your site&#8217;s page structure. Create a page, throw up a WYSIWYG editor, and viola! Some CMS&#8217;s take a more fine grained approach, and consider content in a more abstract light. Content would be comparable to a data structure in a programming language. I believe <a href="http://ez.no/">ezPublish</a> even goes as far as calling content &#8220;classes&#8221;.</li>
<li>Lastly, a CMS should be capable of creating pages which don&#8217;t fall under the rubric of your page structure directly, for example, an article section. You probably don&#8217;t want an entry in your navigation for every single article, but you definitely want a clean url like http://mydomain/articles/this-is-an-article
</li>
</ol>
<p>With that in mind, let&#8217;s talk about the &#8220;theory&#8221; of apostrophe, and how it approaches these scenarios. As far as content, apostrophe seems to have found a ground between the above mentioned approaches. On the one hand, content does not directly equal a page in your site, but <em>can be </em> closely associated with it. On the other hand, content is not relegated to the abstract world of boring data entry forms, but actually real live snippets of html, which can be controlled through boring data entry forms, or an rss feed, or a youtube video, or anything you want if you have some creative ideas.<br />
With apostrophe, the we start out with the concept of a page. A page represents (almost all the time, but we&#8217;ll get to that), a public facing url on your site. Each page is backed by a slug. A page is rendered using standard php + symfony helpers. There is one layout, and each page has a template associated with it. There is no easy way, at the moment, to switch this layout, but there really shouldn&#8217;t be much of a reason why you would have to.<br />
On the layout that comes with apostrophe, are a number of symfony slots, which are filled in at various points by apostrophe. These are generally things like menus or breadcrumbs.<br />
Each page, has more than one &#8220;area&#8221; in it. An area is like a content holder. It can hold various types of content, stacked vertically. Each area has a name and is associated to a page. A template helper is provided to render these areas in your template.<br />
When an area is rendered, and you are logged in with sufficient privileges, you have the ability to add content to this area. These are called slots (not to be confused with symfony slots). There are enough built in slots to put together any run-of-the-mill website fairly easily, and creating custom slots is not terribly difficult. Some of these include, plain text, rich text, video, slideshow, pdf. Each slot comes with a displayable interface (normal mode), and an editing interface (edit mode). The edit mode can be a simple form, or it can be a complex multistep, workflow-engine powered web application (see the image slot). The edit mode is powered by a component called editView. The content for the slots is, wisely, stored as a serialized php array, instead of physical columns in a database table, although the latter is certainly possible if not discouraged. This is somewhat similar to the current trend of NoSQL databases, and somewhat similar to the approach that <a href="http://bret.appspot.com/entry/how-friendfeed-uses-mysql">friendfeed</a> used when scaling their database. It would have been better, in my opinion, to store the information in JSON instead of serialized PHP, or to use an actual NoSQL database, but there is nothing stopping you from implementing your own content slots this way. When the content is not in editing mode, the display is governed by a component called normalView, where you can, of course, massage all your data as you see fit before displaying it in the components template. Each content slot is essentially a module, with two components (editView and normalView), a model class and usually a form as well. This makes it fairly trivial to create custom content slots, especially if you have prior symfony experience.<br />
You also have the option of what is called, under the hood, a singleton area. An area which contains one and only one content slot. There is a special view helper for this as well called a_slot (as opposed to a_area).<br />
By default, each content area is associated with the slug, and therefore the page that its on. In that respect, content and pages are somewhat analogous. For a basic site, this may well give you enough mileage to go. However, the developers realized that there is room for content which is not owned by any particular page, for example, global content. This could be an editable footer or logo which makes its way into the layout. They also recognized that not every page in a website is physically there. They call this concept &#8220;virtual pages&#8221;, and it allows for some very interesting things. Every content area, both infinite and singleton, can be assigned to a &#8220;virtual page&#8221;, and thereby pulled out in any physical page, no matter what slug it has. Virtual pages are distinguished by virtue of not have a leading &#8220;/&#8221; in their slug name, thereby removing them from the realm of the navigation. One use case I came up with, was having a sidebar in the layout, but having the content of the sidebar different for each page. In order to do this, I had to specify a slug that was guaranteed to be unique for each page, so I called it something like &#8220;sidebar-$page->id&#8221;. I will discuss another use case later.<br />
As I mentioned earlier also, a CMS should also be able to handle pages which shouldn&#8217;t exist in your navigation, such as articles. For this, they came up with the concept of engines. Basically, instead of having your page rendered via apostrophe, it gets sent to a regular symfony module, written to certain conventions. You could have an module which renders an article page, based on an id in the url, but this page will still be under the rubric of your site. As an additional bonus, since its a regular symfony module, rendered by a regular symfony template, you can use the apostrophe helpers, and put content areas in a virtual page with a slug derived from the article&#8217;s id. This was the other use case I was referring to earlier.<br />
This cms follows the principle of less is more, and because of that, it is a clean, elegant system, with almost no learning curve.<br />
That is not say it does not have some problems. The admin view requires that the content areas be surrounded by a swath of DIVs. Unfortunately, these DIVs make it into the end user mode. My designer was not so happy to hear that the recommendation was to &#8220;embrace the DIVs&#8221;.<br />
Also, the page gets loaded with a lot of incoherent, redundant, inline javascript. Both inline in the page, and sometimes inlined on the element itself. There is no Javascript framework such as what comes with diem. For example, when you click &#8220;add slot&#8221; in an area, you are greeting with a very eye-appealing dropdown box. Unfortunately, to mimic that behavior seems to require a lot of copy and pasting.<br />
Certain areas of the code also look suspect and &#8220;hackish&#8221; to me. Any class named &#8220;aTools&#8221; with only static methods is certainly a red flag. Of course, symfony 1.x also has code like this as well, but that doesn&#8217;t mean that bad habits should be copied. Virtual pages are implemented, by temporarily switching a global variable (disguised a static variable), which holds the current page&#8217;s slug, for the duration of the rendering, until when the global variable is swapped back to its original state. This feels like hacky code to me.<br />
Over all, I have to certainly commend the developers of apostrophe. They managed to come up with good solutions for some classic problems in web development. They managed to create a tool which is good for end users *and* developers at the same time. Certainly not an easy task.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aviblock.com/blog/2010/04/21/review-of-the-apostrophe-cms-for-symfony/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>The end of the PHP vs Template language debate?</title>
		<link>http://www.aviblock.com/blog/2010/02/10/the-end-of-the-php-vs-template-language-debate/</link>
		<comments>http://www.aviblock.com/blog/2010/02/10/the-end-of-the-php-vs-template-language-debate/#comments</comments>
		<pubDate>Thu, 11 Feb 2010 03:36:39 +0000</pubDate>
		<dc:creator>Avi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[xhp]]></category>

		<guid isPermaLink="false">http://www.aviblock.com/blog/?p=92</guid>
		<description><![CDATA[For years there has been a ferocious debate about whether it is better to abstract away HTML creation with PHP by using a template language, or whether we should stick with PHP itself as the template language. I always thought the best way to go was a with a hybrid. A templating language which resembles [...]]]></description>
			<content:encoded><![CDATA[<p>For years there has been a ferocious debate about whether it is better to abstract away HTML creation with PHP by using a template language, or whether we should stick with PHP itself as the template language. I always thought the best way to go was a with a hybrid. A templating language which resembles XML, sort of like what you get with JSTL. There have been <a href="http://phptal.org/">some</a> <a href="http://flow3.typo3.org/documentation/manuals/fluid/">attempts </a>, which have been pretty good. Facebook, however, just took this <a href="http://www.facebook.com/notes/facebook-engineering/xhp-a-new-way-to-write-php/294003943919">one step further</a>, and integrated XML into PHP with XHP. This is sort of reminicient of <a href="http://blogs.msdn.com/jimoneil/archive/2009/06/15/x-is-for-xml-literal.aspx">XML Literals</a> in VB. They have released the code on <a href="http://github.com/facebook/xhp">github</a> already. The best part about it is that every XML element is represented by a class, leaving room to create sophisticated widgets out of XML tags! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.aviblock.com/blog/2010/02/10/the-end-of-the-php-vs-template-language-debate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CQRS (Command and Query Responsibility Segregation) in PHP</title>
		<link>http://www.aviblock.com/blog/2009/12/10/cqsr-in-php/</link>
		<comments>http://www.aviblock.com/blog/2009/12/10/cqsr-in-php/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 20:57:54 +0000</pubDate>
		<dc:creator>Avi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[command query separation]]></category>
		<category><![CDATA[ddd]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.aviblock.com/blog/?p=82</guid>
		<description><![CDATA[It always seems to me that the PHP world is one step behind the current trends in the &#8220;enterprise world&#8221;. For example, Rails popularized the &#8220;ActiveRecord&#8221; pattern a few years ago. Ever since then, there has been an explosion of ActiveRecord implementations in PHP. Many even mistakenly refer to them as an &#8220;ORM&#8221;, but I [...]]]></description>
			<content:encoded><![CDATA[<p>It always seems to me that the PHP world is one step behind the current trends in the &#8220;enterprise world&#8221;. For example, Rails popularized the &#8220;ActiveRecord&#8221; pattern a few years ago. Ever since then, there has been an explosion of ActiveRecord implementations in PHP. Many even mistakenly refer to them as an &#8220;ORM&#8221;, but I won&#8217;t beat a dead horse here. ActiveRecord is great for your basic run-of-the-mill address book/cookbook/blog type of app, where it basically data driven, and there&#8217;s not much &#8220;business logic&#8221; to go around. For the majority of PHP applications out there, these tools are a god send.<br />
As PHP matures, especially the object model, advanced developers have started to realize the limits of this pattern. Now the big rage is the DataMapper pattern, and DDD. We try to separate out the domain of application, and the holy grail is now transparent persistence. With great tools like Doctrine 2.0 and Object_Freezer, both of which are only possible with the new additions in PHP 5.3, these dreams are becoming a reality.<br />
<span id="more-82"></span><br />
With this approach, which I have tried to follow recently, there are a couple of pointed issues. The biggest is displaying your domain objects. Off the bat, we don&#8217;t want to &#8220;pollute&#8221; our domain with display concerns (although one could argue that displaying the object is a business concern). So if we want to &#8220;drag the data&#8221; out of our domain, we need a lot of ugly &#8220;getters&#8221;, or to leverage the __get magic method. Getters have long been shunned for breaking encapsulation, revealing the &#8220;shape&#8221; of an entity (ie., it should not be so important to us that a customer has a first name), and some other things that don&#8217;t really apply in PHP land. But besides all that, they&#8217;re just so annoying to write.<br />
Additionally, we don&#8217;t necessarily want to have our domain objects show up in our UI like that. The domain objects are not tailored made for consumption of our UI. There are many different presentation concerns such as, what I call the &#8220;Fowler Conundrum&#8221;, where do you specify that negative balances will show up in red, and positive in black? Do you create views which have all this ugly logic in them? Do you add it to your domain? Do you create a view helper for every little presentation concern? What about date formatting. Do you need to bring in a DateTime object in your view, and clutter it up with date formatting code? What if you only need a handful of fields to display&#8230;do we throw in the whole object to the UI and hope for the best?<br />
The answer to this is to add an additional layer. The ViewModel. The ViewModel is shaped for every view in your UI. It contains all the necessary presentation logic.<br />
The question still begs, how do you create these ViewModels? There&#8217;s basically three choices. Getters, displaying to an interface, and using Reflection. All of these feel like you&#8217;re compromising somewhere.<br />
Another problem that I came up with recently is, how do you manage something like an autocomplete field. An autocomplete field takes the letters which have been typed in, and searches the database. So do I now need to search the database, get a bunch of domain objects, translate them in a ViewModel and send it back to the UI?<br />
How about pagination? For efficiency purposes, we obviously want to paginate on the query level. We don&#8217;t want to bring in all our information, and then paginate that&#8230;it defeats (most of) the purpose. So do we have to pollute our repositories with findByPage methods? The other solution is almost as ugly (but it has a lot of elegance to it). In the .NET world, a proposed solution was to return an IQueryable&#8230;an interface that LINQ understands. The idea is, you&#8217;re repository returns an IQueryable (or even better, a special subset of IQueryable that you can call IPageable), and once you get that, you construct the rest of the information as gotten from the ui. This was debated upon for a long time whether 1) Whether this constitutes &#8220;pure DDD&#8221; and 2) Whether it is a good practice to begin with. The PHP version of this could be to return a Zend_Paginator_Adapter_Interface and basically do the same thing.<br />
The latest &#8220;trend&#8221;, of which I don&#8217;t really see anybody speaking about in the PHP world, is that of CQRS. CQRS stands for Command and Query Responsibility Segregation, and it was formally known as CQS, or command query separation. CQS is a basic tenet of OOP, put forth by Bertand Meyer. The idea is simple, every method on an object is either a command (ie., it does something), or it is a query (ie., it retrieves information). A method should not do both (Martin Fowler admits that there are some compelling reasons to violate this, like popping a value from a stack, but in that case, the convenience outweighs the strict and blind adherence to principles).<br />
In the past year of so, this pattern has been expanded on an architectural level. Meaning commands go to the domain, and queries go somewhere else. There are two parts of your system. The commands, which tell your system to do something, and the queries. The queries come from a query repository, which is a stale snapshot of the state of your entities. The commands go to a domain repository, which publish an internal event (which captures the business intent of the command), and an external event to update the data store.<br />
The beauty of this, is that your view models don&#8217;t come from your domain anymore. They come from your query repository. You could retrieve them anyway you want (ORM, TableDataGateway, ActiveRecord or even straight SQL). In fact, the various views on your data could actually be real views in your database, denormalized to flatten relationships, or with only the fields that you need. Also, the internal published events can be stored in an EventStore, and played back to maintain the current state of the entity. This removes almost entirely the &#8220;impendence mismatch&#8221; between objects and the relational database.<br />
I will hopefully right more on this pattern, and how it can be applied to PHP, as I learn more about it myself.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aviblock.com/blog/2009/12/10/cqsr-in-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Templatizer</title>
		<link>http://www.aviblock.com/blog/2009/05/19/templatizer/</link>
		<comments>http://www.aviblock.com/blog/2009/05/19/templatizer/#comments</comments>
		<pubDate>Tue, 19 May 2009 14:07:04 +0000</pubDate>
		<dc:creator>Avi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[add-on]]></category>
		<category><![CDATA[Expression Engine]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.aviblock.com/blog/?p=51</guid>
		<description><![CDATA[I released an extension the other day for EE. You can find it here.
The basic idea is that creating templates in Expression Engine, especially if you don&#8217;t plan to edit them from the CP, can sometimes be a little repetitive and annoying.
Normally with EE, the templates are stored in the database, and you have the [...]]]></description>
			<content:encoded><![CDATA[<p>I released an extension the other day for EE. You can find it <a href="http://expressionengine.com/forums/viewthread/114771/">here</a>.</p>
<p>The basic idea is that creating templates in Expression Engine, especially if you don&#8217;t plan to edit them from the CP, can sometimes be a little repetitive and annoying.<br />
Normally with EE, the templates are stored in the database, and you have the option of <i>also</i> storing them on the filesystem. But in order for them to be recognized by EE, they must reside in the database at least.</p>
<p>Using this extension, you can start your template off as a physical file, and the first time you view it in the browser, it will automatically be recognized by EE and inserted into the database!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aviblock.com/blog/2009/05/19/templatizer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ACL in Zend Framework</title>
		<link>http://www.aviblock.com/blog/2009/03/19/acl-in-zend-framework/</link>
		<comments>http://www.aviblock.com/blog/2009/03/19/acl-in-zend-framework/#comments</comments>
		<pubDate>Thu, 19 Mar 2009 20:21:23 +0000</pubDate>
		<dc:creator>Avi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[Zend_Acl]]></category>

		<guid isPermaLink="false">http://www.aviblock.com/blog/?p=22</guid>
		<description><![CDATA[When I first started using the Zend Framework, one of the most confusing things was the ACL component. Even after I succesfully implemented an ACL solution in my app, something seemed wrong with it.
I would like to argue that the proper use for the Zend ACL is actually impossible, since there is a reported bug [...]]]></description>
			<content:encoded><![CDATA[<p>When I first started using the Zend Framework, one of the most confusing things was the ACL component. Even after I succesfully implemented an ACL solution in my app, something seemed wrong with it.</p>
<p>I would like to argue that the proper use for the Zend ACL is actually impossible, since there is a reported <a href="http://zendframework.com/issues/browse/ZF-1721">bug in the code</a> which, to my knowledge, has not been fixed.</p>
<p>The use case I will discuss is where you want to only authors to edit articles and only to articles authored by themselves. I think this is a fairly common case.<br />
<span id="more-22"></span></p>
<p>How does the ACL help us? The ACL allows the developer to setup access rules for arbitrary resources and arbitrary roles. The key word here is &#8220;arbitrary&#8221;, and I&#8217;ll get back to that in a moment.</p>
<p>My feeling is that when most people start out with the ACL, they assume that resources are controllers (or some combination of module and controller), and permissions are actions.  So, for example, let&#8217;s say you had a controller called &#8220;Article&#8221; with an action called &#8220;edit&#8221;.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> ArticleController <span style="color: #000000; font-weight: bold;">extends</span> Zend_Controller_Action <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> editAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
     <span style="color: #666666; font-style: italic;">//do stuff</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>So an ACL would be set up with something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$acl</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Zend_Acl<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$acl</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Zend_Acl_Resource<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'article'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$acl</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addRole</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Zend_Acl_Role<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'author'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$acl</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">deny</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$acl</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">allow</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'author'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'article'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'edit'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>This looks farely straight forward. Some place before the action is dispatched, like in a plugin, action helper or whatever you want, you would do a check against this acl.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$acl</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isAllowed</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$role</span><span style="color: #339933;">,</span> <span style="color: #000088;">$resource</span><span style="color: #339933;">,</span> <span style="color: #000088;">$permission</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>There are two problems with this approach, one obvious and one not so obvious.</p>
<p>The obvious one is that, while this may be successful in blocking regular users from editing the articles, it doesn&#8217;t block another author from editing the article.</p>
<p>In order to do that, we need to add in an additional assertion:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$acl</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">allow</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'author'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'article'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'edit'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> AssertionIsArticleAuthor<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>The problem then becomes: in this assertion, how do you know which article it is? How do you know who the current author is? These can be very tricky questions. You might have to somehow stick the request object in there, and access the Zend_Auth singleton. While these certaintly are viable solutions, they just &#8220;smell&#8221; bad.</p>
<p>The other not so obvious problem is seen by taking a few steps back and looking at the whole problem from the beginning. The first question to ask is, what exactly are we trying to solve here? We want to restrict access to an article. So what did we do instead? We restricted access to a controller? What kind of sense does that make? Additionally, we are now tying in our ACL implementation to the url structure of the site. That is primarily a function presentation. If we would want to change that, it would require changing our ACL implentation. While Zend_Acl is certainly a &#8220;Zend&#8221; component, it has nothing directly to do with Zend MVC, but this approach ties us down to Zend MVC. What if we decided one day that we did not like the MVC components of ZF and wanted to move to Symfony or <a href="http://www.apteno.net/AptitudeCMS/trac/wiki/MVCnPHPProject">MVCnPHP</a>?</p>
<p>Zend Framework is  primarily a presentation framework. It helps in providing a clear and organized way to bring the presentation layer to the user. And that&#8217;s what it excels at. That, I believe, is the number one reason why they don&#8217;t ship with a &#8220;model&#8221; component. The model layer must be provided by yourself, and this part is probably the hardest part of the whole game. But if you keep some simple principles in mind, and keep focused, you can reapproach this whole problem in a new light.</p>
<p>We&#8217;ll start with our model layer. This should be fully functional without ZF. Pretend you&#8217;re writing a desktop app. Or a shell script. Whether or not the model layer should be tied to the database or separated from that as well, is a different question. </p>
<p>My personal approach, one which is fairly common in the Java world, is to work with Business objects, which are just &#8220;POPOs&#8221;&#8230;Plain Old PHP Classes. These business objects represent all the entities in my application&#8230;but this is a post for later. Let&#8217;s not digress too much.</p>
<p>In our model layer, we have two objects, an Article and an Author.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Article <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$id</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$title</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$body</span><span style="color: #339933;">;</span>
&nbsp;
   <span style="color: #009933; font-style: italic;">/**
   * @var Author
   */</span>
   <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$author</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> Author <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$id</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$name</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Any business logic in your app should either take place within these objects, or within other objects that act as a service layer. Your controllers should either talk to these service layer objects or to the business objects themselves.</p>
<p>When you retrieve data from the database, instead of keeping it around as array, put it in one of these objects. You can also use a custom Zend_Db_Row object for this to if you want to make things really simple.</p>
<p>Now that we&#8217;re dealing with objects, we can see that we want to restrict access to an Article object to the Author object contained within it. So our resource becomes the Article and the role is the Author. How do you define these as resources and roles? All we have to do is have our objects implement the Zend_Acl_Resource and Zend_Acl_Role interfaces! So we will modify the previous code to something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Article implements Zend_Acl_Resource_Interface <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$id</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$title</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$body</span><span style="color: #339933;">;</span>
&nbsp;
   <span style="color: #009933; font-style: italic;">/**
   * @var Author
   */</span>
&nbsp;
   <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$author</span><span style="color: #339933;">;</span>
&nbsp;
   <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getResourceId<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
       <span style="color: #b1b100;">return</span> <span style="color: #0000ff;">'article'</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> Author implements Zend_Acl_Role_Interface <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$id</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$name</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getRoleId<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #0000ff;">'user'</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Now we write our custom assertion:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Chintion_Acl_Assert_AssertIsArticleAuthor implements Zend_Acl_Assert_Interface
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #990000;">assert</span><span style="color: #009900;">&#40;</span>Zend_Acl <span style="color: #000088;">$acl</span><span style="color: #339933;">,</span> Zend_Acl_Role_Interface  <span style="color: #000088;">$author</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">null</span><span style="color: #339933;">,</span>
    Zend_Acl_Resource_Interface <span style="color: #000088;">$article</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #000088;">$privilege</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
          <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">article</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">author</span> <span style="color: #339933;">==</span> <span style="color: #000088;">$author</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Now when you have your Article object, you can take your Author object (which you can either store in Zend_Auth or construct it from the data in Zend_Auth), and do a check like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$acl</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isAllowed</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$author</span><span style="color: #339933;">,</span> <span style="color: #000088;">$article</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Very nice, clean and simple.</p>
<p>Except&#8230;..</p>
<p>It won&#8217;t work. By the time the assertion gets a hold of the instance of Zend_Acl_Role_Interface, its been demoted to plain old Zend_Acl_Role. Ditto for Zend_Acl_Resource_Interface. It doesn&#8217;t have our fancy beefed up role or resource.</p>
<p>This I think is due to the bug report that I linked to at the beginning. Fortunately, for the moment, there&#8217;s a work around:</p>
<p>We have to override the method Zend_Acl::get(Zend_Acl_Resource_Interface $resource) and the method Zend_Acl_Role_Registry::get(Zend_Acl_Role_Interface $role);</p>
<p>To do this, you have to subclass Zend_Acl and overridde the get method as such:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> get<span style="color: #009900;">&#40;</span><span style="color: #000088;">$resource</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$resource</span> instanceof Zend_Acl_Resource_Interface<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$resource</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$resource</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>and similary for Zend_Acl_Role_Registry:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> RoleRegistry <span style="color: #000000; font-weight: bold;">extends</span> Zend_Acl_Role_Registry <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> get<span style="color: #009900;">&#40;</span><span style="color: #000088;">$role</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$role</span> instanceof Zend_Acl_Role_Interface<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #b1b100;">return</span> <span style="color: #000088;">$role</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #b1b100;">return</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$role</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>and in your subclassed Zend_Acl:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_roleRegistry <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> RoleRegistry<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://www.aviblock.com/blog/2009/03/19/acl-in-zend-framework/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Presenting a list of Timezones to the user</title>
		<link>http://www.aviblock.com/blog/2009/03/12/presenting-a-list-of-timezones-to-the-user/</link>
		<comments>http://www.aviblock.com/blog/2009/03/12/presenting-a-list-of-timezones-to-the-user/#comments</comments>
		<pubDate>Thu, 12 Mar 2009 20:41:18 +0000</pubDate>
		<dc:creator>Avi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Expression Engine]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[timezones]]></category>
		<category><![CDATA[usability]]></category>

		<guid isPermaLink="false">http://ablock.webfactional.com/blog/?p=3</guid>
		<description><![CDATA[ 
I first got into timezones when I working on an calendar app which displayed various times of day which are pertinent to Jewish daily life. The app would display calculated times which of course would differ based on the timezone of the given location. As I investigated into timezones, I found them to be fairly [...]]]></description>
			<content:encoded><![CDATA[<p> </p>
<p>I first got into timezones when I working on an <a title="OU Calendar Application" href="http://www.ou.org/holidays/calendar" target="_blank">calendar app</a> which displayed various times of day which are pertinent to Jewish daily life. The app would display calculated times which of course would differ based on the timezone of the given location. As I investigated into timezones, I found them to be fairly complicated. Not all timezones are even on the hour&#8230;some are at 30 minute offsets, some at 45 minutes, and historically there have been even stranger offsets than that.</p>
<p>To make matters worse, there&#8217;s the whole issue of Daylight Saving Time. Apparently some places have it some don&#8217;t. Some countries have a set date for DST, some pick a new one each year depending on circumstances. And of course, DST does not mean only adding one hour. <br />
<span id="more-3"></span><br />
My research led me to what is &#8220;colloquially&#8221; known as the <a title="Olson Database" href="http://www.twinsun.com/tz/tz-link.htm" target="_blank">&#8220;Olson&#8221; database</a>. The Olson database is a <a href="http://article.gmane.org/gmane.comp.time.tz/2496" target="_blank">de facto standard</a> in the world of keeping time. The most recognizable part of the way timezones are identified is the {Continent}/{Location} signature. For example, the timezone that I am in is called &#8220;America/New_York&#8221;. The Olson database tracks all historical information about timezones back at least until 1970. By timezone information, this also means transitions for DST and the GMT offset for both standard time and DST.</p>
<p>The best part of all of this, is that PHP 5 and up has <a title="PHP Support's Timezones" href="http://www.php.net/timezones " target="_blank">built in support</a> for understanding Olson timezones. This means that you all you need is the timezone id (the tzid), and you can have PHP worry about all the timezone and DST calculations.</p>
<p>Recently, I was working on another app which required members to select a timezone. The app is written on top of <a title="Expression Engine" href="http://www.expressionengine.com" target="_blank">Expression Engine</a> which contains a full blown membership system. The membership system includes a timezone setting. Let&#8217;s take a quick look at the what this look like:</p>
<div id="attachment_9" class="wp-caption alignnone" style="width: 1034px"><img class="size-large wp-image-9" title="Screenshot of timezone selection from Expression Engine" src="http://ablock.webfactional.com/blog/wp-content/uploads/2009/03/ss121-1024x350.png" alt="Selecting a timezone in Expression Engine" width="1024" height="350" /><p class="wp-caption-text">Selecting a timezone in Expression Engine</p></div>
<p>Notice the checkbox that says &#8220;Daylight Saving Time&#8221;? This means that the user has to remember, every year, to select that checkbox when DST happens. Not very fun. Expression Engine is written in PHP 4, and the authors <a title="Expression Engine to stay supporting PHP4" href="http://expressionengine.com/blog/entry/i_see_dead_server_side_scripting_languages/" target="_blank">intend to keep that</a>, stubbornly, for as long as possible.</p>
<p>I&#8217;m not here to wrant on Expression Engine (that&#8217;s for another time), but either way, this would not suit my purposes. I can&#8217;t rely on users remembering to &#8220;spring forward&#8221; when they have to.</p>
<p>The alternative is to provide a list based on the Olson database. The problem is that, as of this post, their are 560 tzid&#8217;s in the database, and they are not &#8220;friendly&#8221; nor recognizable to anybody but geeks. </p>
<p>I started looking around on the Interwebs trying to see what other people came up with. There was a <a href="http://stackoverflow.com/questions/119672/how-would-you-organize-a-timezone-dropdown" target="_blank">question</a> on <a title="stackoverflow.com" href="http://www.stackoverflow.com" target="_blank">Stackoverflow.com</a> which hit the nail on the head, but anybody answering the question missed the point completely.</p>
<p>Eventually I realized that I must present a list similar to Expression Engine&#8217;s list, but which has the values as Olson tzid&#8217;s. The first step was to clean up the list a little. Much of the information is redundant, and only there for historical purposes. For instance, until 2006, much of <a href="http://www.mccsc.edu/time.html" target="_blank">Indiana did not observe DST.</a> After 2006, however, the story changed. This explains why there are so many Olson tzid&#8217;s with Indiana in them. However, for all practical purposes, they&#8217;re the same.</p>
<p>The question is, what defines them as the same? I determined the best way would be to look at the DST transition date (if applicable), and the resulting offsets and compare them. Fortunately, PHP has a function that does this&#8230;<a href="http://us.php.net/manual/en/function.timezone-transitions-get.php" target="_blank">timezone_transitions_get()</a>.</p>
<p>My idea was to pull in all the timezones and their transistions into excel and sort them by offset, and transition dates to identify which tzids are similar. After that, to figure out a friendly name to call them.</p>
<p>Doing more research I found somebody made a <a title="spreadsheet for timezones" href="http://www.timdavis.com.au/data/olson-time-zone-database-to-standard-windows-time-zone-v01/ " target="_blank">spreadsheet</a> which tried to map Windows timezone names to Olson tzid&#8217;s. I used this a base reference for the names I chose, although I found not all the data in that spreadsheet was accurate (one day I will submit my changes to the author). Some timezones I had to come up with my own names like &#8220;America/Havana&#8221; which has different rules for any place in its timezone. I decided to call this (GMT-05:00) Cuba for lack of anything else.</p>
<p>In the end, I came up with a list of about 80 or so timezones, and I&#8217;m somewhat proud of my results:</p>
<p>Here is the list:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;option value=&quot;Pacific/Midway&quot;&gt;(GMT-11:00) Midway Island, Samoa&lt;/option&gt;
&lt;option value=&quot;America/Adak&quot;&gt;(GMT-10:00) Hawaii-Aleutian&lt;/option&gt;
&lt;option value=&quot;Etc/GMT+10&quot;&gt;(GMT-10:00) Hawaii&lt;/option&gt;
&lt;option value=&quot;Pacific/Marquesas&quot;&gt;(GMT-09:30) Marquesas Islands&lt;/option&gt;
&lt;option value=&quot;Pacific/Gambier&quot;&gt;(GMT-09:00) Gambier Islands&lt;/option&gt;
&lt;option value=&quot;America/Anchorage&quot;&gt;(GMT-09:00) Alaska&lt;/option&gt;
&lt;option value=&quot;America/Ensenada&quot;&gt;(GMT-08:00) Tijuana, Baja California&lt;/option&gt;
&lt;option value=&quot;Etc/GMT+8&quot;&gt;(GMT-08:00) Pitcairn Islands&lt;/option&gt;
&lt;option value=&quot;America/Los_Angeles&quot;&gt;(GMT-08:00) Pacific Time (US &amp; Canada)&lt;/option&gt;
&lt;option value=&quot;America/Denver&quot;&gt;(GMT-07:00) Mountain Time (US &amp; Canada)&lt;/option&gt;
&lt;option value=&quot;America/Chihuahua&quot;&gt;(GMT-07:00) Chihuahua, La Paz, Mazatlan&lt;/option&gt;
&lt;option value=&quot;America/Dawson_Creek&quot;&gt;(GMT-07:00) Arizona&lt;/option&gt;
&lt;option value=&quot;America/Belize&quot;&gt;(GMT-06:00) Saskatchewan, Central America&lt;/option&gt;
&lt;option value=&quot;America/Cancun&quot;&gt;(GMT-06:00) Guadalajara, Mexico City, Monterrey&lt;/option&gt;
&lt;option value=&quot;Chile/EasterIsland&quot;&gt;(GMT-06:00) Easter Island&lt;/option&gt;
&lt;option value=&quot;America/Chicago&quot;&gt;(GMT-06:00) Central Time (US &amp; Canada)&lt;/option&gt;
&lt;option value=&quot;America/New_York&quot;&gt;(GMT-05:00) Eastern Time (US &amp; Canada)&lt;/option&gt;
&lt;option value=&quot;America/Havana&quot;&gt;(GMT-05:00) Cuba&lt;/option&gt;
&lt;option value=&quot;America/Bogota&quot;&gt;(GMT-05:00) Bogota, Lima, Quito, Rio Branco&lt;/option&gt;
&lt;option value=&quot;America/Caracas&quot;&gt;(GMT-04:30) Caracas&lt;/option&gt;
&lt;option value=&quot;America/Santiago&quot;&gt;(GMT-04:00) Santiago&lt;/option&gt;
&lt;option value=&quot;America/La_Paz&quot;&gt;(GMT-04:00) La Paz&lt;/option&gt;
&lt;option value=&quot;Atlantic/Stanley&quot;&gt;(GMT-04:00) Faukland Islands&lt;/option&gt;
&lt;option value=&quot;America/Campo_Grande&quot;&gt;(GMT-04:00) Brazil&lt;/option&gt;
&lt;option value=&quot;America/Goose_Bay&quot;&gt;(GMT-04:00) Atlantic Time (Goose Bay)&lt;/option&gt;
&lt;option value=&quot;America/Glace_Bay&quot;&gt;(GMT-04:00) Atlantic Time (Canada)&lt;/option&gt;
&lt;option value=&quot;America/St_Johns&quot;&gt;(GMT-03:30) Newfoundland&lt;/option&gt;
&lt;option value=&quot;America/Araguaina&quot;&gt;(GMT-03:00) UTC-3&lt;/option&gt;
&lt;option value=&quot;America/Montevideo&quot;&gt;(GMT-03:00) Montevideo&lt;/option&gt;
&lt;option value=&quot;America/Miquelon&quot;&gt;(GMT-03:00) Miquelon, St. Pierre&lt;/option&gt;
&lt;option value=&quot;America/Godthab&quot;&gt;(GMT-03:00) Greenland&lt;/option&gt;
&lt;option value=&quot;America/Argentina/Buenos_Aires&quot;&gt;(GMT-03:00) Buenos Aires&lt;/option&gt;
&lt;option value=&quot;America/Sao_Paulo&quot;&gt;(GMT-03:00) Brasilia&lt;/option&gt;
&lt;option value=&quot;America/Noronha&quot;&gt;(GMT-02:00) Mid-Atlantic&lt;/option&gt;
&lt;option value=&quot;Atlantic/Cape_Verde&quot;&gt;(GMT-01:00) Cape Verde Is.&lt;/option&gt;
&lt;option value=&quot;Atlantic/Azores&quot;&gt;(GMT-01:00) Azores&lt;/option&gt;
&lt;option value=&quot;Europe/Belfast&quot;&gt;(GMT) Greenwich Mean Time : Belfast&lt;/option&gt;
&lt;option value=&quot;Europe/Dublin&quot;&gt;(GMT) Greenwich Mean Time : Dublin&lt;/option&gt;
&lt;option value=&quot;Europe/Lisbon&quot;&gt;(GMT) Greenwich Mean Time : Lisbon&lt;/option&gt;
&lt;option value=&quot;Europe/London&quot;&gt;(GMT) Greenwich Mean Time : London&lt;/option&gt;
&lt;option value=&quot;Africa/Abidjan&quot;&gt;(GMT) Monrovia, Reykjavik&lt;/option&gt;
&lt;option value=&quot;Europe/Amsterdam&quot;&gt;(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna&lt;/option&gt;
&lt;option value=&quot;Europe/Belgrade&quot;&gt;(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague&lt;/option&gt;
&lt;option value=&quot;Europe/Brussels&quot;&gt;(GMT+01:00) Brussels, Copenhagen, Madrid, Paris&lt;/option&gt;
&lt;option value=&quot;Africa/Algiers&quot;&gt;(GMT+01:00) West Central Africa&lt;/option&gt;
&lt;option value=&quot;Africa/Windhoek&quot;&gt;(GMT+01:00) Windhoek&lt;/option&gt;
&lt;option value=&quot;Asia/Beirut&quot;&gt;(GMT+02:00) Beirut&lt;/option&gt;
&lt;option value=&quot;Africa/Cairo&quot;&gt;(GMT+02:00) Cairo&lt;/option&gt;
&lt;option value=&quot;Asia/Gaza&quot;&gt;(GMT+02:00) Gaza&lt;/option&gt;
&lt;option value=&quot;Africa/Blantyre&quot;&gt;(GMT+02:00) Harare, Pretoria&lt;/option&gt;
&lt;option value=&quot;Asia/Jerusalem&quot;&gt;(GMT+02:00) Jerusalem&lt;/option&gt;
&lt;option value=&quot;Europe/Minsk&quot;&gt;(GMT+02:00) Minsk&lt;/option&gt;
&lt;option value=&quot;Asia/Damascus&quot;&gt;(GMT+02:00) Syria&lt;/option&gt;
&lt;option value=&quot;Europe/Moscow&quot;&gt;(GMT+03:00) Moscow, St. Petersburg, Volgograd&lt;/option&gt;
&lt;option value=&quot;Africa/Addis_Ababa&quot;&gt;(GMT+03:00) Nairobi&lt;/option&gt;
&lt;option value=&quot;Asia/Tehran&quot;&gt;(GMT+03:30) Tehran&lt;/option&gt;
&lt;option value=&quot;Asia/Dubai&quot;&gt;(GMT+04:00) Abu Dhabi, Muscat&lt;/option&gt;
&lt;option value=&quot;Asia/Yerevan&quot;&gt;(GMT+04:00) Yerevan&lt;/option&gt;
&lt;option value=&quot;Asia/Kabul&quot;&gt;(GMT+04:30) Kabul&lt;/option&gt;
&lt;option value=&quot;Asia/Yekaterinburg&quot;&gt;(GMT+05:00) Ekaterinburg&lt;/option&gt;
&lt;option value=&quot;Asia/Tashkent&quot;&gt;(GMT+05:00) Tashkent&lt;/option&gt;
&lt;option value=&quot;Asia/Kolkata&quot;&gt;(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi&lt;/option&gt;
&lt;option value=&quot;Asia/Katmandu&quot;&gt;(GMT+05:45) Kathmandu&lt;/option&gt;
&lt;option value=&quot;Asia/Dhaka&quot;&gt;(GMT+06:00) Astana, Dhaka&lt;/option&gt;
&lt;option value=&quot;Asia/Novosibirsk&quot;&gt;(GMT+06:00) Novosibirsk&lt;/option&gt;
&lt;option value=&quot;Asia/Rangoon&quot;&gt;(GMT+06:30) Yangon (Rangoon)&lt;/option&gt;
&lt;option value=&quot;Asia/Bangkok&quot;&gt;(GMT+07:00) Bangkok, Hanoi, Jakarta&lt;/option&gt;
&lt;option value=&quot;Asia/Krasnoyarsk&quot;&gt;(GMT+07:00) Krasnoyarsk&lt;/option&gt;
&lt;option value=&quot;Asia/Hong_Kong&quot;&gt;(GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi&lt;/option&gt;
&lt;option value=&quot;Asia/Irkutsk&quot;&gt;(GMT+08:00) Irkutsk, Ulaan Bataar&lt;/option&gt;
&lt;option value=&quot;Australia/Perth&quot;&gt;(GMT+08:00) Perth&lt;/option&gt;
&lt;option value=&quot;Australia/Eucla&quot;&gt;(GMT+08:45) Eucla&lt;/option&gt;
&lt;option value=&quot;Asia/Tokyo&quot;&gt;(GMT+09:00) Osaka, Sapporo, Tokyo&lt;/option&gt;
&lt;option value=&quot;Asia/Seoul&quot;&gt;(GMT+09:00) Seoul&lt;/option&gt;
&lt;option value=&quot;Asia/Yakutsk&quot;&gt;(GMT+09:00) Yakutsk&lt;/option&gt;
&lt;option value=&quot;Australia/Adelaide&quot;&gt;(GMT+09:30) Adelaide&lt;/option&gt;
&lt;option value=&quot;Australia/Darwin&quot;&gt;(GMT+09:30) Darwin&lt;/option&gt;
&lt;option value=&quot;Australia/Brisbane&quot;&gt;(GMT+10:00) Brisbane&lt;/option&gt;
&lt;option value=&quot;Australia/Hobart&quot;&gt;(GMT+10:00) Hobart&lt;/option&gt;
&lt;option value=&quot;Asia/Vladivostok&quot;&gt;(GMT+10:00) Vladivostok&lt;/option&gt;
&lt;option value=&quot;Australia/Lord_Howe&quot;&gt;(GMT+10:30) Lord Howe Island&lt;/option&gt;
&lt;option value=&quot;Etc/GMT-11&quot;&gt;(GMT+11:00) Solomon Is., New Caledonia&lt;/option&gt;
&lt;option value=&quot;Asia/Magadan&quot;&gt;(GMT+11:00) Magadan&lt;/option&gt;
&lt;option value=&quot;Pacific/Norfolk&quot;&gt;(GMT+11:30) Norfolk Island&lt;/option&gt;
&lt;option value=&quot;Asia/Anadyr&quot;&gt;(GMT+12:00) Anadyr, Kamchatka&lt;/option&gt;
&lt;option value=&quot;Pacific/Auckland&quot;&gt;(GMT+12:00) Auckland, Wellington&lt;/option&gt;
&lt;option value=&quot;Etc/GMT-12&quot;&gt;(GMT+12:00) Fiji, Kamchatka, Marshall Is.&lt;/option&gt;
&lt;option value=&quot;Pacific/Chatham&quot;&gt;(GMT+12:45) Chatham Islands&lt;/option&gt;
&lt;option value=&quot;Pacific/Tongatapu&quot;&gt;(GMT+13:00) Nuku'alofa&lt;/option&gt;
&lt;option value=&quot;Pacific/Kiritimati&quot;&gt;(GMT+14:00) Kiritimati&lt;/option&gt;</pre></div></div>

<p>If anybody can offer any improvements to this or a different suggestion altogether, that would be great.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aviblock.com/blog/2009/03/12/presenting-a-list-of-timezones-to-the-user/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>
