<?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>niden.net &#187; How-To</title>
	<atom:link href="http://www.niden.net/category/how-to/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.niden.net</link>
	<description>Boldly goes where no coder has gone before... and other ramblings :)</description>
	<lastBuildDate>Tue, 07 Sep 2010 04:10:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Create an inexpensive hourly remote backup [How-To]</title>
		<link>http://www.niden.net/2010/08/how-to-create-an-inexpensive-hourly-remote-backup/</link>
		<comments>http://www.niden.net/2010/08/how-to-create-an-inexpensive-hourly-remote-backup/#comments</comments>
		<pubDate>Sun, 22 Aug 2010 03:03:45 +0000</pubDate>
		<dc:creator>Nikolaos Dimopoulos</dc:creator>
				<category><![CDATA[Backup]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[Installation]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Storage]]></category>

		<guid isPermaLink="false">http://www.niden.net/?p=1224</guid>
		<description><![CDATA[There are two kinds of people, those who backup regularly, and those that never had a hard drive fail. I love the above quote. It is so true and I believe everyone should evaluate how much their data (emails, documents, files) is worth to them and, based on that value, create a backup strategy that suits them. I know for sure that if I ever lost the pictures and videos of my family I would be devastated since those are irreplaceable.]]></description>
			<content:encoded><![CDATA[<p></p><blockquote><p>There are two kinds of people, those who backup regularly, and those that never had a hard drive fail</p></blockquote>
<p>As you can tell <a href="http://www.niden.net/2010/08/subversion-backup-how-to/">the above is my favorite quote</a>. It is so true and I believe everyone should evaluate how much their data (emails, documents, files) is worth to them and, based on that value, create a backup strategy that suits them. I know for sure that if I ever lost the pictures and videos of my family I would be devastated since those are irreplaceable.</p>
<p>So the question is how can I have an inexpensive backup solution? All my documents and emails are stored in Google, since my domain is on <a href="http://www.google.com/a/">Google Apps</a>. What happens to the live/development servers though that host all my work? I program on a daily basis and the code has to be backed up regularly so as to avoid any hard drive failures and thus result in loss of time and money.</p>
<p>So here is my solution. I have an old computer (IBM Thincentre) which I decided to beef up a bit. I bought 4Gb of RAM from eBay for less than $100 for it. Although this is was not necessary since my solution would be based on Linux (<a href="http://www.gentoo.org">Gentoo</a> in particular), I wanted to have faster compilation times for packages.</p>
<p>I bought two external drives (750Gb and 500Gb respectively) and one 750Gb internal drive. I already have a 120Gb hard drive in the computer. The two external ones are connected to the computer using USB while the internal ones are connected using SATA.</p>
<p>The external drives are formatted using NTFS while the whole computer is built using ReiserFS.</p>
<p>Here is the approach:</p>
<ul>
<li>I have installed and have a working Gentoo installation on the machine</li>
<li>I have an active Internet connection</li>
<li>I have installed LVM on the machine and set up the core system on the 120Mb drive while the 500Mb is on LVM</li>
<li>I have 300Mb active on the LVM (from the available 500Mb)</li>
<li>I have generated a public SSH key (I will need this to exchange it with the target servers</li>
<li>I have mounted the internal 500Mb drive to the <strong>/storage</strong> folder</li>
<li>I have mounted the external USB 750Mb drive to the <strong>/backup_hourly</strong> folder</li>
<li>I have mounted the external USB 500Mb drive to the <strong>/backup_daily</strong> folder</li>
</ul>
<p>Here is how my backup works:</p>
<p>Every hour a script runs. The script uses rsync to syncrhonize files and folders from a remote server locally. Those files and folders are kept in relevant server named subfolders in the <strong>/storage</strong> folder (remember this is my LVM). So for instance my subfolders will be <strong>/storage/beryllium.niden.net</strong>, <strong>/storage/nitrogen.niden.net</strong>, <strong>/storage/argon.niden.net</strong> etc.</p>
<p>Once the rsync completes, the script continues by compressing the relevant &#8216;server&#8217; folder and creates the compressed file with a date-time stamp on its name.</p>
<p>When all compressions are completed, if the time that the script has executed is midnight, the backups are moved from the <strong>/storage</strong> folder to the <strong>/backup_daily</strong> folder (which has the external USB 500Gb mounted). If it is any other time, the files are moved in the <strong>/backup_hourly</strong> folder (which has the external USB 750Gb mounted).</p>
<p>This way I ensure that I keep a lot of backups (daily and hourly ones). The backups are being recycled, so older ones get deleted. The amount of data that you need to archive as well as the storage space you have available dictate how far back you can go in your hourly and daily cycles.</p>
<p>So let&#8217;s get down to business. The script itself:</p>
<pre>#!/bin/bash
DATE=`date +%Y-%m-%d-%H-%M`
DATE2=`date +%Y-%m-%d`
DATEBACK_HOUR=`date --date='6 days ago' +%Y-%m-%d`
DATEBACK_DAY=`date --date='60 days ago' +%Y-%m-%d`
FLAGS="--archive --verbose --numeric-ids --delete --rsh='ssh'"
BACKUP_DRIVE="/storage"
DAY_USB_DRIVE="/backup_daily"
HOUR_USB_DRIVE="/backup_hourly"</pre>
<p>These are some variables that I need for the script to work. The <strong>DATE</strong> and <strong>DATE2</strong> are used to date/time stamp the backups, while the <strong>DATEBACK_</strong>* are used to clear previous backups. In this case it is set to 6 days ago (for my system). It can be set to whatever you want provided that you do not run out of space.</p>
<p>The <strong>FLAGS</strong> variable keeps the rsync command options while the <strong>BACKUP_DRIVE</strong>, <strong>DAY_USB_DRIVE</strong> and <strong>HOUR_USB_DRIVE</strong> hold the locations of the rsync folders, daily backup and hourly backup sorage areas.</p>
<p>The script works with arrays. I have 4 arrays to do the work and the 3 of them must have exactly the same elements.</p>
<pre># RSync Information
rsync_info[1]="beryllium.niden.net html rsync"
rsync_info[2]="beryllium.niden.net db rsync"
rsync_info[3]="nitrogen.niden.net html rsync"
rsync_info[4]="nitrogen.niden.net html db"
rsync_info[5]="nitrogen.niden.net html svn"
rsync_info[6]="argon.niden.net html rsync"</pre>
<p>This is the first array which holds descriptions to what needs to be done as far as source is concerned. This gets appended to the log and helps me identify what step I am in.</p>
<pre># RSync Source Folders
rsync_source[1]="beryllium.niden.net:/var/www/localhost/htdocs/"
rsync_source[2]="beryllium.niden.net:/niden_backup/db/"
rsync_source[3]="nitrogen.niden.net:/var/www/localhost/htdocs/"
rsync_source[4]="nitrogen.niden.net:/niden_backup/db"
rsync_source[5]="nitrogen.niden.net:/niden_backup/svn"
rsync_source[6]="argon.niden.net:/var/www/localhost/htdocs/"</pre>
<p>This array holds the source host and folder. Remember that I have already exchanged SSH keys with each server, therefore when the script runs there is a direct connection to the source server. If you need to keep things a bit more secure for you, then you will need to alter the contents of the rsync_source array so that it reflects the user that you log in with as well as the password.</p>
<pre># RSync Target Folders
rsync_target[1]="beryllium.niden.net/html/"
rsync_target[2]="beryllium.niden.net/db/"
rsync_target[3]="nitrogen.niden.net/html/"
rsync_target[4]="nitrogen.niden.net/db/"
rsync_target[5]="nitrogen.niden.net/svn/"
rsync_target[6]="argon.niden.net/html/"</pre>
<p>This array holds the target locations for the rsync. These folders exist in my case under the <strong>/storage</strong> subfolder.</p>
<pre># GZip target files
servers[1]="beryllium.niden.net"
servers[2]="nitrogen.niden.net"
servers[3]="argon.niden.net"</pre>
<p>This array holds the names of the folders to be archived. These are the folders directly under the <strong>/storage</strong> folder and I am also using this array for the prefix of the compressed files. The suffix of the compressed files is a date/time stamp.</p>
<p>Here is how the script evolves:</p>
<pre>echo "BACKUP START"  &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
date &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log

echo "BACKUP START"  &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
date  &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log

# Loop through the RSync process
element_count=${#rsync_info[@]}
let "element_count = $element_count + 1"
index=1
while [ "$index" -lt "$element_count" ]
do
    echo ${rsync_info[$index]} &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    rsync $FLAGS ${rsync_source[$index]} $BACKUP_DRIVE/${rsync_target[$index]} &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    let "index = $index + 1"
done</pre>
<p>The snippet above loops through the <strong>rsync_info</strong> array and prints out the information in the log file. Right after that it uses the <strong>rsync_source</strong> and <strong>rsync_target</strong> arrays (as well as the <strong>FLAGS</strong> variable) to rsync the contents of the source server with the local folder. Remember that all three arrays have to be identical in size (<strong>rsync_info</strong>, <strong>rsync_source</strong>, <strong>rsync_target</strong>).</p>
<p>The next thing to do is zip the data (I loop through the servers array)</p>
<pre># Looping to GZip data
element_count=${#servers[@]}
let "element_count = $element_count + 1"
index=1
while [ "$index" -lt "$element_count" ]
do
    echo "GZip ${servers[$index]}" &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    tar cvfz $BACKUP_DRIVE/${servers[$index]}-$DATE.tgz $BACKUP_DRIVE/${servers[$index]} &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    let "index = $index + 1"
done</pre>
<p>The compression method I use is tar/gzip. I found it to be fast with a good compression ratio. You can choose anything you like.</p>
<p>Now I need to delete old files from the drives and copy the files on those drives. I use the servers array again.</p>
<pre># Looping to copy the produced files (if applicable) to the daily drive
element_count=${#servers[@]}
let "element_count = $element_count + 1"
index=1

while [ "$index" -lt "$element_count" ]
do
    # Copy the midnight files
    echo "Removing old daily midnight files" &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    rm -f $DAY_USB_DRIVE/${servers[$index]}/${servers[$index]}-$DATEBACK_DAY*.* &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    echo "Copying daily midnight files" &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    cp -v $BACKUP_DRIVE/${servers[$index]}-$DATE2-00-*.tgz $DAY_USB_DRIVE/${servers[$index]}  &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    rm -f $BACKUP_DRIVE/${servers[$index]}-$DATE2-00-*.tgz &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log

    # Now copy the files in the hourly
    echo "Removing old hourly files" &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    rm -f $HOUR_USB_DRIVE/${servers[$index]}/${servers[$index]}-$DATEBACK_HOUR*.* &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    echo "Copying daily midnight files" &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    cp -v $BACKUP_DRIVE/${servers[$index]}-$DATE.tgz $HOUR_USB_DRIVE/${servers[$index]} &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    rm -f $HOUR_USB_DRIVE/${servers[$index]}/${servers[$index]}-$DATEBACK*.* &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log
    let "index = $index + 1"
done

echo "BACKUP END"  &gt;&gt; $BACKUP_DRIVE/logs/$DATE.log</pre>
<p>The last part of the script loops through the servers array and:</p>
<ol>
<li>Deletes the old files (recycling of space) from the daily backup drive (<strong>/storage/backup_daily</strong>) according to the <strong>DATEBACK_DAY</strong> variable. If the files are not found a warning will appear in the log.</li>
<li>Copies the daily midnight file to the daily drive (if the file does not exist it will simply echo a warning in the log &#8211; I do not worry about warnings of this kind in the log file and was too lazy to use an IF EXISTS condition)</li>
<li>Removes the daily midnight file from the <strong>/storage</strong> drive.</li>
</ol>
<p>The reason I am using copy and then remove instead of the move (<strong>mv</strong>) command is that I have found this method to be faster.</p>
<p>Finally the same thing happens with the hourly files</p>
<ol>
<li>Old files are removed (<strong>DATEBACK_HOUR</strong> variable)</li>
<li>Hourly file gets copied to the <strong>/backup_hourly</strong> drive</li>
<li>Hourly file gets deleted from the <strong>/storage</strong> drive</li>
</ol>
<p>All I need now is to add the script in my crontab and let it run every hour.</p>
<p><strong>NOTE</strong>: The first time you will run the script you will need to do it manually (not in a cron job). The reason behind it is that the first time rsync will need to download all the contents of the source servers/folders in the <strong>/storage</strong> drive so as to create an exact mirror. Once that lengthy step is done, the script can be added in the crontab. Subsequent runs of the script will download only the changed/deleted files.</p>
<p>This method can be very effective while not using a ton of bandwidth every hour. I have used this method for the best part of a year now and it has saved me a couple of times.</p>
<p>The last thing I need to present you is the backup script that I have for my databases. As you notice above the source folder of beryllium.niden.net as far as databases are concerned is <strong>beryllium.niden.net/db/</strong>. What I do is I dump and zip the databases every hour on my servers. Although this is not a very efficient way of doing things and it adds to the bandwidth consumption every hour (since the dump will create a new file every hour) I have the following script running on my database servers every hour at the 45th minute:</p>
<pre>#!/bin/bash

DBUSER=mydbuser
DBPASS='dbpassword'
DBHOST=localhost
BACKUPFOLDER="/niden_backup"
DBNAMES="`mysql --user=$DBUSER --password=$DBPASS --host=$DBHOST --batch --skip-column-names -e "show databases"| sed 's/ /%/g'`"
OPTIONS="--quote-names --opt --compress "

# Clear the backu folder
rm -fR $BACKUPFOLDER/db/*.*

for i in $DBNAMES; do
    echo Dumping Database: $i
    mysqldump --user=$DBUSER --password=$DBPASS --host=$DBHOST $OPTIONS $i &gt; $BACKUPFOLDER/db/$i.sql
    tar cvfz $BACKUPFOLDER/db/$i.tqz $BACKUPFOLDER/db/$i.sql
    rm -f $BACKUPFOLDER/db/$i.sql
done</pre>
<p>That&#8217;s it.</p>
<p>The backup script can be downloaded <a href="http://www.niden.net/wp-content/uploads/2010/01/hourly_backup.txt">here</a>.</p>
<p>Update: The metric units for the drives were GB not MB. Thanks to <a href="http://www.codeutopia.net">Jani Hartikainen</a> for pointing it out.</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-6325600846885391";
/* www.niden.net Blog 468x60 */
google_ad_slot = "1288968183";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h4  class="related_post_title">Related Posts</h4><ul class="related_post"><li>December 10, 2009 -- <a href="http://www.niden.net/2009/12/faster-rsync-and-emerge-in-gentoo/" title="Faster rsync and emerge in Gentoo [How-To]">Faster rsync and emerge in Gentoo [How-To]</a> (0)</li><li>November 16, 2009 -- <a href="http://www.niden.net/2009/11/gentoo-stage-1-installation/" title="Gentoo Stage 1 Installation [How-To]">Gentoo Stage 1 Installation [How-To]</a> (1)</li><li>August 1, 2010 -- <a href="http://www.niden.net/2010/08/subversion-backup-how-to/" title="Subversion Backup [How-To]">Subversion Backup [How-To]</a> (5)</li><li>January 10, 2010 -- <a href="http://www.niden.net/2010/01/how-to-create-a-ssl-certificate-linux/" title="Create a SSL Certificate (Linux) [How-To]">Create a SSL Certificate (Linux) [How-To]</a> (4)</li><li>November 24, 2009 -- <a href="http://www.niden.net/2009/11/chromium-os-part-3/" title="Chromium OS Part 3 [How-To]">Chromium OS Part 3 [How-To]</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.niden.net/2010/08/how-to-create-an-inexpensive-hourly-remote-backup/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Google Apps and Google Accounts merge [Information][How-To]</title>
		<link>http://www.niden.net/2010/08/google-apps-and-google-accounts-merge-information-howto/</link>
		<comments>http://www.niden.net/2010/08/google-apps-and-google-accounts-merge-information-howto/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 12:08:33 +0000</pubDate>
		<dc:creator>Nikolaos Dimopoulos</dc:creator>
				<category><![CDATA[Google]]></category>
		<category><![CDATA[Google Apps]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[Information]]></category>
		<category><![CDATA[Google Accounts]]></category>

		<guid isPermaLink="false">http://www.niden.net/?p=1156</guid>
		<description><![CDATA[Anyone that has a Google Apps account and wants to access other services like Google Reader, Google Voice etc. knows that the username and password of the Google Apps account does not work for these services, since those are not available for Google Apps accounts. To get around this limitation, what you could do (and what [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Anyone that has a Google Apps account and wants to access other services like <a href="http://reader.google.com">Google Reader</a>, <a href="http://voice.google.com">Google Voice</a> etc. knows that the username and password of the Google Apps account does not work for these services, since those are not available for Google Apps accounts. To get around this limitation, what you could do (and what I have done in the past) is to sign up for a new Google Account with the same email address as your Google Apps account.  This of course creates confusion at times, duplication of data and disassociation of services. The most obvious example of this is on an Android device. To use my phone, I need to sign in with my Google Apps account. However, to use my Google Voice number, I  have to use sign in again for that service but now using my Google Account (which uses the same email address). This works but I still have to keep two sets of contacts &#8211; one for the Google Apps and one in Google Voice.</p>
<p>According to Google, <a href="http://productideas.appspot.com/#25/e=2199b">9 of the top 20 requests</a> from Google Apps customers are for their accounts to work with more services from Google. To facilitate this, the Google Apps account had to be merged with the Google Account. This page in Google Apps Help that <a href="http://www.google.com/support/accounts/bin/answer.py?hl=en&amp;answer=182174">describes</a> the transition.</p>
<p>Unfortunately this was not a simple flip of a switch for Google. <a href="http://googleenterprise.blogspot.com/2010/05/more-google-applications-coming-for.html">Significant infrastructure changes</a> had to be in place prior to the merging of the accounts. We were promised that this change would be in place by fall and we have not been disappointed. Google is rolling out the update slowly but if you want to &#8216;speed up&#8217; the process, you can <a href="https://spreadsheets1.google.com/a/google.com/viewform?hl=en&amp;formkey=dGdfTTA2eGhFT0c0SDVLXzMzMFNwUUE6MA#gid=0">sign up</a> for an early round of testing of the new infrastructure. I have signed up for several of my Google Apps domains a couple of weeks ago.</p>
<p>I am happy to announce that one of my domains has already gone through the merge process. The domain is <a href="http://wwww.BeautyAndTheGeek.IT">BeautyAndTheGeek.IT</a> which is a Google Apps Premier edition. My other domains that are hosted in Google Apps have not transitioned yet and I suspect that Google is first merging Premium accounts, then Educational, Government and it will finish up with the Standard edition of Google Apps, which kind of makes sense (paid customers first!).</p>
<h3>Email Invitation</h3>
<div id="attachment_1174" class="wp-caption aligncenter" style="width: 300px">
	<a href="http://www.niden.net/wp-content/uploads/2010/08/8-Google-Apps-Initial-Email.png"><img class="size-medium wp-image-1174 " title="8-Google-Apps-Initial-Email" src="http://www.niden.net/wp-content/uploads/2010/08/8-Google-Apps-Initial-Email-300x286.png" alt="Invitation Email to the Admin" width="300" height="286" /></a>
	<p class="wp-caption-text">Invitation Email to the Admin</p>
</div>
<p>The day before yesterday I received an email inviting me to participate in the new infrastructure change and merge the Google Apps accounts with the Google Accounts of my users.</p>
<p>The merge process works as follows:</p>
<p>- If your Google Apps account email address <strong><span style="text-decoration: underline;">has never been used</span></strong> to access Google products such as Google Reader, Google Voice, Google Code etc. then your Google Apps account will be converted to a Google Account.</p>
<p>- If your Google Apps account email address <strong><span style="text-decoration: underline;">has been used</span></strong> to access Google products such as Google Reader, Google Voice, Google Code etc. then your Google Apps account is conflicting with your Google Account. This <a href="http://www.google.com/support/a/bin/answer.py?answer=184937">page</a> in Google Apps Administrator Help provides an overview of conflicting accounts. In short both of your accounts will merge and the data will be associated with your Google Apps account, which will now be the same as your Google Account.</p>
<p>There are certain limitations to this merge (as one would expect <img src='http://www.niden.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ). These are as follows:</p>
<ol>
<li>If the offline feature is enabled in GMail, the user has to synchronize before the transition. If they don&#8217;t, they will lose their offline messages.</li>
<li>Offline Google Calendar doesn&#8217;t work for Google Apps accounts that have transitioned.</li>
<li>The following Google products don&#8217;t work with Google Apps accounts that have transitioned:
<ul>
<li>Android Market for Developers</li>
<li>Google Extra Storage (bummer)</li>
<li>Health (bummer again)</li>
<li>PowerMeter</li>
<li>Profiles</li>
<li>Web History</li>
<li>YouTube</li>
</ul>
</li>
<li>The purchase of additional Google Storage is currently unavailable for Google Apps accounts. No storage can be purchased for a Google Apps account, although it will be available later this year. If a user account has already purchased extra storage (like I have) in an existing Google Account, the storage will remain in that account and will not transfer to the respective Google Apps account after the transition.</li>
<li>Delegating email only works with the same account type (i.e. Google Apps)</li>
<li>Any Picasa Web Album, Profile, or Wave usernames cannot be moved from an existing account to your Google Apps account.</li>
</ol>
<p>Resources: <a href="http://www.google.com/support/a/bin/answer.py?answer=182034">Transition readiness checklist</a>, <a href="http://www.google.com/support/a/bin/answer.py?answer=184937">Conflicting accounts</a>, <a href="http://www.google.com/support/a/bin/answer.py?answer=181872">Early adopters</a>, <a href="http://www.google.com/support/a/bin/answer.py?answer=172732">Additional storage for Google Apps</a>, <a href="http://www.google.com/support/a/bin/topic.py?topic=28917">Google Apps Administrator Help Center</a></p>
<h2><strong>The process</strong></h2>
<h3><strong>Google Apps &#8211; Dashboard Warning</strong></h3>
<div id="attachment_1180" class="wp-caption aligncenter" style="width: 300px">
	<a href="http://www.niden.net/wp-content/uploads/2010/08/0-Google-Apps-Warning.png"><img class="size-medium wp-image-1180 " title="0-Google-Apps-Warning" src="http://www.niden.net/wp-content/uploads/2010/08/0-Google-Apps-Warning-300x63.png" alt="Dashboard Warning" width="300" height="63" /></a>
	<p class="wp-caption-text">Dashboard Warning</p>
</div>
<p>Once I logged in my Google Apps Administration area, the Dashboard presented a new notice at the top. In short the notice states that new services will be available to the Google Apps accounts. This will be achieved with the transition of the Google Apps Account to a Google Account. The update is free and Google will automatically roll it out on <strong>September 30, 2010</strong>.</p>
<p>Resource: <a href="http://www.google.com/apps/intl/en/business/index.html">Google Apps core suite</a></p>
<h3>Google Apps &#8211; Understand Transition</h3>
<div id="attachment_1158" class="wp-caption aligncenter" style="width: 300px">
	<a href="http://www.niden.net/wp-content/uploads/2010/08/1-Google-Apps-Understand-Transition.png"><img class="size-medium wp-image-1158" title="1-Google-Apps-Understand-Transition" src="http://www.niden.net/wp-content/uploads/2010/08/1-Google-Apps-Understand-Transition-300x95.png" alt="Understanding Transition" width="300" height="95" /></a>
	<p class="wp-caption-text">Understanding Transition</p>
</div>
<p>Clicking the &#8220;<strong>Get Started</strong>&#8221; button at the bottom of the notice will start a wizard that helps with the transition of the domain&#8217;s accounts to Google accounts of your users (some or all). The first screen contains information that aids in understanding the transition and what is involved.   Moving to the new infrastructure will update your control panel and give you control over which Google services your users can access with their accounts.</p>
<p>Resource: <a href="http://www.google.com/support/a/bin/answer.py?answer=182034">Transition readiness checklist</a>, <a href="http://www.google.com/support/a/bin/topic.py?topic=28917">Google Apps Administrator Help Center</a></p>
<h3>Google Apps &#8211; New Services</h3>
<div id="attachment_1160" class="wp-caption aligncenter" style="width: 300px">
	<a href="http://www.niden.net/wp-content/uploads/2010/08/2-Google-Apps-Review-New-Services.png"><img class="size-medium wp-image-1160" title="2-Google-Apps-Review-New-Services" src="http://www.niden.net/wp-content/uploads/2010/08/2-Google-Apps-Review-New-Services-300x126.png" alt="Review New Services" width="300" height="126" /></a>
	<p class="wp-caption-text">Review New Services</p>
</div>
<p>Based on the services that are available for your domain user accounts, the screen above might be slightly different. It does however give you (the administrator) the ability to enable or disable services for your users. Note that turning off a service will disallow your users to sign up for that service using their Google Apps account for your domain. It will however not stop them from using a totally different Google Account (personal for instance) to access that service.</p>
<h3>Google Apps &#8211; Notify Conflicting Accounts</h3>
<div id="attachment_1162" class="wp-caption aligncenter" style="width: 300px">
	<a href="http://www.niden.net/wp-content/uploads/2010/08/3-Google-Apps-Notify-Conflicting-Accounts.png"><img class="size-medium wp-image-1162" title="3-Google-Apps-Notify-Conflicting-Accounts" src="http://www.niden.net/wp-content/uploads/2010/08/3-Google-Apps-Notify-Conflicting-Accounts-300x92.png" alt="Notify Conflicting Accounts" width="300" height="92" /></a>
	<p class="wp-caption-text">Notify Conflicting Accounts</p>
</div>
<p>Confirming the new services, the wizard will display a new screen, that will allow you to notify those users that have conflicting accounts. This screen provides information on how many users have conflicting accounts (in my case only 1), what happens to those accounts (the merge process) and what should you do as the administrator. Google will not provide information on which of your users have conflicting accounts. What they will however do, is offer you a temporary email address and an email template, that you can use to email your users. The email template is shown in the &#8220;<em>Google Apps &#8211; Email to User</em>&#8220; section below.</p>
<h3>Google Apps &#8211; Select Users</h3>
<div id="attachment_1164" class="wp-caption aligncenter" style="width: 300px">
	<a href="http://www.niden.net/wp-content/uploads/2010/08/4-Google-Apps-Select-Users.png"><img class="size-medium wp-image-1164" title="4-Google-Apps-Select-Users" src="http://www.niden.net/wp-content/uploads/2010/08/4-Google-Apps-Select-Users-300x86.png" alt="Select Users" width="300" height="86" /></a>
	<p class="wp-caption-text">Select Users</p>
</div>
<p>Clicking &#8220;<strong>Continue</strong>&#8220;, brings up the User Selection screen. Here the administrator can select whose account will be transitioned for now. You can choose to pilot test this transition with a small set of users or everyone. The difference is that if you choose a small set of users to pilot test this transition, you can revert their accounts back to what they were prior to this step. If you choose &#8220;<em>Everyone</em>&#8221; from this screen, the change will be across the organization and cannot be undone. Reminder here that the transition will happen either way by the end of September, 2010. Finally you have the option to inform the users when their account transition is complete. This generates an email (in English) to the user with relevant information. You can see the email in section &#8220;<em>Google Apps &#8211; Email to User</em>&#8221; below.</p>
<p>Resource: <a href="http://www.google.com/support/a/bin/answer.py?answer=181872">Early adopters</a></p>
<h3>Google Apps &#8211; Confirmation</h3>
<div id="attachment_1166" class="wp-caption aligncenter" style="width: 300px">
	<a href="http://www.niden.net/wp-content/uploads/2010/08/5-Google-Apps-Confirm.png"><img class="size-medium wp-image-1166" title="5-Google-Apps-Confirm" src="http://www.niden.net/wp-content/uploads/2010/08/5-Google-Apps-Confirm-300x146.png" alt="Confirmation" width="300" height="146" /></a>
	<p class="wp-caption-text">Confirmation</p>
</div>
<p>Clicking &#8220;<strong>Continue</strong>&#8220;again will bring up the final screen which is the confirmation page. Google is very thorough and I like the confirmation screen. The information in this screen is a summary of what the wizard collected in previous steps. You (the administrator) will have to confirm in several places that you have understood the process, read the agreement and then accept the whole process. Clicking &#8220;<strong>I accept. Start the transition.</strong>&#8221; will make things happen <img src='http://www.niden.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Resources: <a href="http://www.google.com/support/a/bin/answer.py?answer=182034">Transition readiness checklist</a></p>
<p><strong>Google Apps &#8211; Transition in progress</strong></p>
<div id="attachment_1168" class="wp-caption aligncenter" style="width: 300px">
	<a href="http://www.niden.net/wp-content/uploads/2010/08/6-Google-Apps-Transition-In-Progress.png"><img class="size-medium wp-image-1168" title="6-Google-Apps-Transition-In-Progress" src="http://www.niden.net/wp-content/uploads/2010/08/6-Google-Apps-Transition-In-Progress-300x25.png" alt="Transition in Progress" width="300" height="25" /></a>
	<p class="wp-caption-text">Transition in Progress</p>
</div>
<p>Navigating back to the dashboard, you will see a message notifying you that there is a transition in place for the accounts of your domain and can take up to 24 hours to be completed. This serves as a reminder on what has just happened. The notice will disappear once the transition is completed.</p>
<h3>Google Apps &#8211; Email to User</h3>
<div id="attachment_1170" class="wp-caption aligncenter" style="width: 300px">
	<a href="http://www.niden.net/wp-content/uploads/2010/08/7-Google-Apps-Email-To-User.png"><img class="size-medium wp-image-1170" title="7-Google-Apps-Email-To-User" src="http://www.niden.net/wp-content/uploads/2010/08/7-Google-Apps-Email-To-User-300x207.png" alt="Email to User" width="300" height="207" /></a>
	<p class="wp-caption-text">Email to User</p>
</div>
<p>If you (the administrator) chose to notify your users of this transition (see step <em>Select Users</em> above), they will receive an email like the one shown above. If you chose to notify your users with a different message then that message should have been sent to the temporary email address that Google has provided (see step <em>Notifying Conflicting Accounts</em> above)</p>
<p>Resources: <a href="http://www.google.com/support/accounts/bin/answer.py?answer=181692">Data ownership</a>, <a href="http://www.google.com/support/a/bin/answer.py?answer=182034">Transition readiness checklist</a>, <a href="http://www.google.com/support/a/bin/topic.py?topic=28917">Google Apps Administrator Help Center</a></p>
<h3>Google Apps - Email to User after Transition</h3>
<div id="attachment_1172" class="wp-caption aligncenter" style="width: 300px">
	<a href="http://www.niden.net/wp-content/uploads/2010/08/7-Google-Apps-Email-To-User-After.png"><img class="size-medium wp-image-1172" title="7-Google-Apps-Email-To-User-After" src="http://www.niden.net/wp-content/uploads/2010/08/7-Google-Apps-Email-To-User-After-300x279.png" alt="Email to User after Transition" width="300" height="279" /></a>
	<p class="wp-caption-text">Email to User after Transition</p>
</div>
<p>Finally another email will be sent to the user summarizing what has happened with their account. This email contains links to additional resources.</p>
<p>Resources: <a href="http://www.google.com/options/">List of products</a>, <a href="http://www.google.com/support/accounts/bin/answer.py?answer=181703">New sign in option</a>,  <a href="http://www.google.com/support/accounts/bin/answer.py?answer=181692">Data ownership</a>, <a href="http://www.whatbrowser.org/en/">What is a browser?</a>, <a href="http://www.google.com/support/accounts/bin/answer.py?hl=en&amp;answer=182343">Using multiple accounts</a>, <a href="http://www.google.com/support/a/bin/topic.py?topic=28917">Help Center for Admins</a>, <a href="http://www.google.com/support/a/bin/topic.py?topic=28917">Google Apps Administrator Help Center</a></p>
<h3>Google Apps - User Login message for Account Merge</h3>
<p style="text-align: center;"><a href="http://www.niden.net/wp-content/uploads/2010/08/9-Google-Apps-User-Perspective.png"><img class="aligncenter" title="9-Google-Apps-User-Perspective" src="http://www.niden.net/wp-content/uploads/2010/08/9-Google-Apps-User-Perspective-300x114.png" alt="User Login Message for Account Merge" width="300" height="114" /></a></p>
<p>Once the transition operation is completed, the next time the user logs in their account, they will see the screen above. In short this screen informs the user of what has happened and provides links to online resources for help. The user must click &#8220;<strong>I accept. Continue to my account.</strong>&#8221; for them to have access to their account. This is  a one off process.</p>
<p>Resources: <a href="http://www.google.com/support/a/bin/topic.py?topic=28917">Google Apps Administrator Help Center</a>, <a href="http://www.google.com/support/a/bin/answer.py?hl=en&amp;answer=60762">Google Security and Privacy</a>, <a href="http://www.google.com/support/accounts/bin/answer.py?hl=en&amp;answer=182343">Using multiple accounts</a>, <a href="http://www.google.com/apps/intl/en/terms/user_terms.html">Terms of Service</a></p>
<h3>Conclusion</h3>
<p>Without a doubt this is a huge step forward for Google and for us as admins or users. The ability to have a single sign on to use their products not only helps them but us by simplifying everything. That also means that if a hacker guesses that my password is &#8220;<strong>password1</strong>&#8221; they have access to all my Google related services&#8230; but oh well <img src='http://www.niden.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Joking apart though, I am really excited that this change has finally occurred. I am guessing that the next steps would be to give users or admins the ability to purchase additional storage for a single account is something that in my view will make quite a lot of money for Google. A lot of people will want to keep all their emails and are nearing or have reached their email quota. Administrators would be happy to pay for certain users that have depleted their email storage allocation without converting their whole Google Apps edition to the Premier one. After all, if your organization has 100 users and 5 of them are near capacity, even if you pay $20 per user it will cost $100 per year. If however the whole account is changed to a Premier account (with 25Gb per mailbox) the cost will go up to $5,000.</p>
<p>Some questions come to mind:</p>
<ol>
<li>Will the user be able to purchase storage for all services or just for email?</li>
<li>Will the 1Gb limit from Docs be lifted and will it be combined with storage for mail?</li>
<li>$20 a year gives you 80Gb in Picasa. Will Google follow that model or change it? According to the <a href="http://www.google.com/support/a/bin/answer.py?answer=172732">Additional storage for Google Apps</a> page it appears that it will be more expensive now to have more space.</li>
<li>If storage is so cheap (Picasa) will it be extended to Google Documents? It appears that 7.5Gb is enough for the vast majority of users as far as email is concerned, but 1Gb for Docs is not enough. For a society moving towards a full electronic document storage this could help a lot.</li>
</ol>
<p>Still a long way to go until everything clears up. I am not sure that Google has all the answers yet but they are moving forward and this is the most encouraging news of all!</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-6325600846885391";
/* www.niden.net Blog 468x60 */
google_ad_slot = "1288968183";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h4  class="related_post_title">Related Posts</h4><ul class="related_post"><li>November 24, 2009 -- <a href="http://www.niden.net/2009/11/chromium-os-part-3/" title="Chromium OS Part 3 [How-To]">Chromium OS Part 3 [How-To]</a> (1)</li><li>November 24, 2009 -- <a href="http://www.niden.net/2009/11/chromium-os-part-2/" title="Chromium OS Part 2 [How-To]">Chromium OS Part 2 [How-To]</a> (2)</li><li>November 24, 2009 -- <a href="http://www.niden.net/2009/11/chromium-os-part-1/" title="Chromium OS Part 1 [How-To]">Chromium OS Part 1 [How-To]</a> (3)</li><li>November 16, 2009 -- <a href="http://www.niden.net/2009/11/google-apps/" title="Google Apps [Review]">Google Apps [Review]</a> (0)</li><li>August 21, 2010 -- <a href="http://www.niden.net/2010/08/how-to-create-an-inexpensive-hourly-remote-backup/" title="Create an inexpensive hourly remote backup [How-To]">Create an inexpensive hourly remote backup [How-To]</a> (3)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.niden.net/2010/08/google-apps-and-google-accounts-merge-information-howto/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Subversion Backup [How-To]</title>
		<link>http://www.niden.net/2010/08/subversion-backup-how-to/</link>
		<comments>http://www.niden.net/2010/08/subversion-backup-how-to/#comments</comments>
		<pubDate>Sun, 01 Aug 2010 17:41:05 +0000</pubDate>
		<dc:creator>Nikolaos Dimopoulos</dc:creator>
				<category><![CDATA[Backup]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Subversion]]></category>
		<category><![CDATA[HowTo]]></category>

		<guid isPermaLink="false">http://www.niden.net/?p=1134</guid>
		<description><![CDATA[I will start this post once again with the words of a wise man: There are two kinds of people, those who backup regularly, and those that never had a hard drive fail So the moral of the story here is backup often. If something is to happen, the impact on your operations will be [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>I will start this post once again with the words of a wise man:</p>
<blockquote><p>There are two kinds of people, those who backup regularly, and those that never had a hard drive fail</p></blockquote>
<p>So the moral of the story here is <strong>backup often</strong>. If something is to happen, the impact on your operations will be minimal if your backup strategy is in place and operational.</p>
<p>There are a lot of backup scenarios and strategies. Most of them suggest a backup once a day, usually at the early hours of the day. This however might not work very well with a fast paced environment where data changes several times per hour. This kind of environment is usually a software development one.</p>
<p>If you have chosen <a href="http://subversion.tigris.org/">Subversion</a> to be your software version control software then you will need a backup strategy for your repositories. Since the code changes very often, this strategy cannot rely on the daily backup schedule. The reason being is that, in software, a day&#8217;s worth of work usually costs a lot more than the actual daily rate of the programmers.</p>
<p>Below are some of the scripts I have used over the years for my incremental backups, that I hope will help you too. You are more than welcome to copy and paste the scripts and use them  or modify them to suit your needs. Please note though that the scripts are provided as is and that you must check your backup strategy with a full backup/restore cycle. I cannot assume responsibility of something that might happen in your system.</p>
<p>Now that the &#8216;legal&#8217; stuff are out of the way, here are the different strategies that you can adopt. <img src='http://www.niden.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>svn-hot-backup</h3>
<p>This is a script that is provided with <a href="http://subversion.tigris.org/">Subversion</a>. It copies (and compresses if requested) the whole repository to a specified location. This technique allows for a full copy of the repository to be moved to a different location. The target location can be a resource on the local machine or a network resource. You can also backup on the local drive and then as a next step transfer the target files to an offsite location with <a href="http://en.wikipedia.org/wiki/File_Transfer_Protocol">FTP</a>, <a href="http://en.wikipedia.org/wiki/Secure_copy">SCP</a>, <a href="http://www.samba.org/rsync/">RSync</a> or any other mechanism you prefer.</p>
<pre class="brush:bash">#!/bin/bash

# Grab listing of repositories and copy each
# repository accordingly

SVNFLD="/var/svn"
BACKUPFLD="/backup"

# First clean up the backup folder
rm -f $BACKUPFLD/*.*

for i in $(ls -1v $SVNFLD); do
    if [ $i != 'conf' ]; then
        /usr/bin/svn-hot-backup --archive-type=bz2 $SVNFLD/$i $BACKUPFLD
    fi
done</pre>
<p>This script will create a copy of each of your repositories and compress it as a bz2 file in the target location. Note that I am filtering for &#8216;conf&#8217;. The reason being is that I have a conf file with some configuration scripts in the same SVN folder. You can adapt the script to your needs to include/exclude repositories/folders as needed.</p>
<p>This technique gives the ability to immediately restore a repository (or more than one) by changing the configuration file of SVN to point to the backup location. If you run the script every hour or so then your downtime and loss will be minimal, should something happens.</p>
<p>There are some configuration options that you can tweak by editing the actual svn-hot-backup script. In Gentoo it is located under <em>/usr/bin/</em>. The default number of backups (<em>num_backups</em>) that the script will keep is 64. You can choose 0 to &#8216;keep them all&#8217; but you can adjust it according to your storage or your backup strategy.</p>
<p>One last thing to note is that you can change the compression mechanism by changing the parameter of the <em>&#8211;archive-type</em> option. The compression types supported are gz (.tar.gz), bz2 (.tar.bz2) and zip (.zip)</p>
<h3>Full backup using dump</h3>
<p>This method is similar to the svn-hot-backup. It works by &#8216;dumping&#8217; the repository in a portable file format and compressing it.</p>
<pre class="brush:bash">#!/bin/bash

# Grab listing of folders and dump each
# repository accordingly

SVNFLD="/var/svn"
BACKUPFLD="/backup"

# First clean up the backup folder
rm -f $BACKUPFLD/svn/*.*

for i in $(ls -1v $SVNFLD); do
    if [ $i != 'conf' ]; then
        svnadmin dump $SVNFLD/$i/ &gt; $BACKUPFLD/$i.svn.dump
        tar cvfz $BACKUPFLD/svn/$i.tgz $BACKUPFLD/$i.svn.dump
        rm -f $BACKUPFLD/$i.svn.dump
    fi
done</pre>
<p>As you can see, this version does the same thing as the <em>svn-hot-backup</em>. It does however give you a bit more control over the whole backup process and allows for a different compression mechanism &#8211; since the compression happens on a separate line in the script.</p>
<p><strong>NOTE:</strong> If you use the <em>hotcopy</em> parameter in <em>svnadmin</em> (<em>svnadmin hotcopy &#8230;..</em>) you will effectively be duplicating the behavior of <em>svn-hot-backup</em>.</p>
<h3>Incremental backup using dump based on revision</h3>
<p>This last method is what I use at work. We have our repositories backed up externally and we rely on the backup script to have everything backed up and transferred to the external location within an hour, since our backup strategy is an hourly backup. We have discovered that sometimes the size of a repository can cause problems with the transfer, since the Internet line will not be able to transfer the files across in the allocated time. This happened once in the past with a repository that ended up being 500Mb (don&#8217;t ask <img src='http://www.niden.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ).</p>
<p>So in order to minimize the upload time, I have altered the script to dump each repository&#8217;s revision in a separate file. Here is how it works:</p>
<p>We backup using rsync. This way the &#8216;old&#8217; files are not being transferred.</p>
<p>Every hour the script loops through each repository name and does the following:</p>
<ol>
<li>Checks if the *<em>.latest</em> file exists in the <em>svn-latest</em> folder. If no, then it sets the <em>LASTDUMP</em> variable to 0.</li>
<li>If the file exists, it reads it and obtains the number stored in that file. It then stores that number incremented by 1 in the <em>LASTDUMP</em> variable.</li>
<li>Checks the number of the latest revision and stores it in the <em>LASTVERSION</em> variable</li>
<li>It loops through the repository, dumps each revision (<em>LASTDUMP</em> to <em>LASTVERSION</em>) and compresses it</li>
</ol>
<p>This method creates new files every hour so long as new code has been added in each repository via the checkin process. The rsync command will then pick only the new files and nothing else, therefore the data transferred is reduced to a bare minimum allowing easily for hourly external backups. With this method we can also restore a single revision in a repository if we need to.</p>
<p>The script that achieves that is as follows:</p>
<pre class="brush:bash">#!/bin/bash

# Grab listing of folders and dump each
# repository accordingly

SVNFLD="/var/svn"
BACKUPFLD="/backup"
CHECKFLD=$BACKUPFLD/svn-latest

for i in $(ls -1v $SVNFLD); do
    if [ $i != 'conf' ]; then
        # Find out what our 'start' will be
        if [ -f $CHECKFLD/$i.latest ]
        then
            LATEST=$(cat $CHECKFLD/$i.latest)
            LASTDUMP=$LATEST+1
        else
            LASTDUMP=0
        fi

        # This is the 'end' for the loop
        LASTREVISION=$(svnlook youngest $SVNFLD/$i/)

        for ((r=$LASTDUMP; r&lt; =$LASTREVISION; r++ )); do
            svnadmin dump $SVNFLD/$i/ --revision $r &gt; $BACKUPFLD/$i-$r.svn.dump
            tar cvfz $BACKUPFLD/svn/$i-$r.tgz $BACKUPFLD/$i-$r.svn.dump
            rm -f $BACKUPFLD/$i-$r.svn.dump
            echo $r &gt; $CHECKFLD/$i.latest
        done
    fi
done</pre>
<h3>Conclusion</h3>
<p>You must <strong>always</strong> backup your data. The frequency is dictated by the rate that your data updates and how critical your data is. I hope that the methods presented in this blog post will complement your programming and source control should you choose to adopt them.</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-6325600846885391";
/* www.niden.net Blog 468x60 */
google_ad_slot = "1288968183";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h4  class="related_post_title">Related Posts</h4><ul class="related_post"><li>August 21, 2010 -- <a href="http://www.niden.net/2010/08/how-to-create-an-inexpensive-hourly-remote-backup/" title="Create an inexpensive hourly remote backup [How-To]">Create an inexpensive hourly remote backup [How-To]</a> (3)</li><li>January 10, 2010 -- <a href="http://www.niden.net/2010/01/how-to-create-a-ssl-certificate-linux/" title="Create a SSL Certificate (Linux) [How-To]">Create a SSL Certificate (Linux) [How-To]</a> (4)</li><li>December 10, 2009 -- <a href="http://www.niden.net/2009/12/faster-rsync-and-emerge-in-gentoo/" title="Faster rsync and emerge in Gentoo [How-To]">Faster rsync and emerge in Gentoo [How-To]</a> (0)</li><li>November 16, 2009 -- <a href="http://www.niden.net/2009/11/gentoo-stage-1-installation/" title="Gentoo Stage 1 Installation [How-To]">Gentoo Stage 1 Installation [How-To]</a> (1)</li><li>November 24, 2009 -- <a href="http://www.niden.net/2009/11/chromium-os-part-3/" title="Chromium OS Part 3 [How-To]">Chromium OS Part 3 [How-To]</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.niden.net/2010/08/subversion-backup-how-to/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Design Patterns – Factory [Series][How-To]</title>
		<link>http://www.niden.net/2010/02/design-patterns-factory-series-how-to/</link>
		<comments>http://www.niden.net/2010/02/design-patterns-factory-series-how-to/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 13:55:35 +0000</pubDate>
		<dc:creator>Nikolaos Dimopoulos</dc:creator>
				<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Series]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://www.niden.net/?p=530</guid>
		<description><![CDATA[A note about these series. It appears that Giorgio Sironi and I had the same idea regarding Design Patterns and blogging about them. He covers the Factory design pattern thoroughly in his blog post, which is recommended reading. The Problem I started off my IT career as a network administrator. This was back in the [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>A note about these series. It appears that <a href="http://giorgiosironi.blogspot.com">Giorgio Sironi</a> and I had the same idea regarding Design Patterns and blogging about them. He covers the <a href="http://giorgiosironi.blogspot.com/2010/01/practical-php-patterns-factory-method.html">Factory</a> design pattern thoroughly in his blog post, which is recommended reading.</p>
<h3>The Problem</h3>
<p>I started off my IT career as a network administrator. This was back in the good old Novell 3.11 days. After that it was Novell 4.0, Microsoft Servers etc. Following that I got more and more involved with Visual Basic and when Microsoft decided to move everyone to .NET I chose not to follow and ended up coding in PHP.</p>
<p>Since my programming knowledge came from within (studying, reading articles, trial and error), the problems that I was facing on a daily basis are the same as almost every developer faces. One particularly challenging problem that I had in the VB days as well as the PHP days was repetition of code and how to eliminate it.</p>
<p>When I started programming for the <a href="http://ffff.niden.net">Ferrari Fans Fun Forecast</a> site I was running the site using my apartment&#8217;s ADSL line. In the beginning there were only 20 users or so, therefore that setup was fine. The scripts were VBScript against a local instance of Microsoft SQL Server. Later on though, I switched to PHP while keeping Microsoft SQL Server.</p>
<h3>Initial implementation</h3>
<p>I knew that I would have to change my scripts later on to work against MySQL since I was to change the hosting of the site. Through laziness or poor design (you can pick either or both <img src='http://www.niden.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ) I chose to create a class for Microsoft SQL and later on I would just change it to the MySQL. It seemed the easiest thing to do at the time.</p>
<p>So my class was something like:</p>
<pre class="brush:php">class DbMSSQL
{
    private $_conn = null;

    public function connect()
    {
         // Connect
        // This is where we have the connection parameters
        include_once 'connection.inc.php';

        $this-&gt;_conn = mssql_connect($host, $user, $password);
        if (!$this-&gt;_conn) {
            throw new Exception('Cannot connect to the database.');
        }
    }

    public function disconnect()
    {
         // Disconnect
        mssql_close($this-&gt;_conn);
    }

    public function selectdb()
    {
         // Select the db
        $db = mssql_select_db($database, $this-&gt;_conn);
        if (!$db) {
            throw new Exception('Cannot select the database');
        }
    }

    public function query($sql)
    {
	    // Query the db
        $_result = mssql_query($sql);

        if (!$_result) {
            throw new Exception('Error in query : ' . $sql);
        }

        $data = array();

        while ($row = mssql_fetch_assoc($_result)) {
            $data[$row['id']] = $row;
        }

        mssql_free_result($_result);

        return $data;
    }
}
?&gt;</pre>
<p>Everything worked fine so I did not worry about a thing. A few months later though I was forced to move the database (as I expected) to MySQL. I could not move everything in one go so I had to move some of the tables initially and a week later everything else.</p>
<p>To tackle this requirement I created a second class to handle operations against MySQL. The class that I ended up with was:</p>
<pre class="brush:php">class DbMySQL
{
    private $_conn = null;

    public function connect()
    {
         // Connect
        // This is where we have the connection parameters
        include_once 'connection.inc.php';

        $this-&gt;_conn = mysql_connect($host, $user, $password);
        if (!$this-&gt;_conn) {
            throw new Exception('Cannot connect to the database :' . mysql_error());
        }
    }

    public function disconnect()
    {
         // Disconnect
        mysql_close($this-&gt;_conn);
    }

    public function selectdb()
    {
         // Select the db
        $db = mysql_select_db($database, $this-&gt;_conn);
        if (!$db) {
            throw new Exception('Cannot select the database : ' . mysql_error());
        }
    }

    public function query($sql)
    {
	    // Query the db
        $_result = mysql_query($sql);

        if (!$_result) {
            throw new Exception('Error in query : ' . mysql_error() . "\n" . $sql);
        }

        $data = array();

        while ($row = mysql_fetch_assoc($_result)) {
            $data[$row['id']] = $row;
        }

        mysql_free_result($_result);

        return $data;
    }
}
?&gt;</pre>
<p>You can easily see the problem here. There is a lot of repetition in the code, not so much as the actual method properties but the methods themselves. Both classes have connect(), disconnect(), selectdb() and query() as methods. In reality the code changes only slightly since the call for an operation against Microsoft SQL Server is <strong>mssql_*</strong> while for MySQL is <strong>mysql_*</strong>. During the transition week I was in programming hell. At some point I mixed the class names, I was trying to read and update the wrong server etc. (see <a href="http://codeutopia.net">Jani Hartikainen</a>&#8216;s post about <a href="http://codeutopia.net/blog/2010/01/28/6-programming-project-mistakes-you-should-avoid/">6 programming project mistakes you should avoid</a> &#8211; I did all that!).</p>
<p>That week though taught me that I need to pay more attention in designing rather than going full speed ahead with programming and later on paying the consequences.</p>
<p>After thorough research, I discovered a library that would support both platforms. The library that I found was <a href="http://adodb.sourceforge.net/">ADOdb</a> which is a perfect example of the Factory Pattern. I used that library later on for a different project, but just looking at the code and understanding the flow of operations as well as the implementation of the pattern itself was invaluable to me.</p>
<p><strong>Interfaces</strong></p>
<p>First of all I need to explain what an interface is and why we need them. According to <a href="http://php.net/manual/en/language.oop5.interfaces.php">PHP.net</a>:</p>
<blockquote><p>Object interfaces allow you to create code which specifies which methods a class must implement, without having to define how these methods are handled.</p></blockquote>
<p>So imagine an interface something like a graft, a blueprint on what I need to construct. The Interface will have the common methods and properties that I need to implement.</p>
<p>When dealing with database connections to two different database servers (Microsoft SQL Server and MySQL), I can clearly define a few methods that will follow CRUD (Create, Read, Update, Delete). Those are:</p>
<ol>
<li>Connect to the database server</li>
<li>Select database</li>
<li>Insert record</li>
<li>Delete record</li>
<li>Update record</li>
<li>Select record(s)</li>
<li>Close connection to the database server</li>
</ol>
<p>My interface would therefore be:</p>
<pre class="brush:php">interface iDatabase
{
    public function connect();
    public function disconnect();
    public function selectdb();
    public function query($sql);
}
?&gt;</pre>
<h3>Design Patterns &#8211; Factory</h3>
<p>A class implementing the Factory Pattern is like a car manufacturing plant producing three different cars on the same assembly line. All cars have common characteristics like 4 wheels, 4 doors (well most of them), a steering wheel, a dashboard etc. and all of them perform certain operations i.e. drive, reverse etc.</p>
<p>In my problem earlier I could have used the Factory Pattern to create one class that would have implemented my blueprint, the interface which defines the CRUD operations that I need. So based on the above, the implementation will result in three classes.</p>
<h5>MSSQL class &#8211; stored in the file Db_mssql.php</h5>
<pre class="brush:php">class Db_mssql implements iDatabase
{
    private $_conn = null;

    public function connect()
    {
         // Connect
        // This is where we have the connection parameters
        include_once 'connection.inc.php';

        $this-&gt;_conn = mssql_connect($host, $user, $password);
        if (!$this-&gt;_conn) {
            throw new Exception('Cannot connect to the database.');
        }
    }

    public function disconnect()
    {
         // Disconnect
        mssql_close($this-&gt;_conn);
    }

    public function selectdb()
    {
         // Select the db
        $db = mssql_select_db($database, $this-&gt;_conn);
        if (!$db) {
            throw new Exception('Cannot select the database');
        }
    }

    public function query($sql)
    {
	    // Query the db
        $_result = mssql_query($sql);

        if (!$_result) {
            throw new Exception('Error in query : ' . $sql);
        }

        $data = array();

        while ($row = mssql_fetch_assoc($_result)) {
            $data[$row['id']] = $row;
        }

        mssql_free_result($_result);

        return $data;
    }
}
?&gt;</pre>
<h5>MySQL class &#8211; stored in the file Db_mysql.php</h5>
<pre class="brush:php">class Db_mysql implements iDatabase
{
    private $_conn = null;

    public function connect()
    {
         // Connect
        // This is where we have the connection parameters
        include_once 'connection.inc.php';

        $this-&gt;_conn = mysql_connect($host, $user, $password);
        if (!$this-&gt;_conn) {
            throw new Exception('Cannot connect to the database :' . mysql_error());
        }
    }

    public function disconnect()
    {
         // Disconnect
        mysql_close($this-&gt;_conn);
    }

    public function selectdb()
    {
         // Select the db
        $db = mysql_select_db($database, $this-&gt;_conn);
        if (!$db) {
            throw new Exception('Cannot select the database : ' . mysql_error());
        }
    }

    public function query($sql)
    {
	    // Query the db
        $_result = mysql_query($sql);

        if (!$_result) {
            throw new Exception('Error in query : ' . mysql_error() . "\n" . $sql);
        }

        $data = array();

        while ($row = mysql_fetch_assoc($_result)) {
            $data[$row['id']] = $row;
        }

        mysql_free_result($_result);

        return $data;
    }
}
?&gt;</pre>
<p>Notice that both these classes are almost identical to the initial implementation shown earlier in this post. The only difference is that they are both implementing the iDatabase interface.</p>
<p>So what is different now? The class that implements the Factory Pattern.</p>
<pre class="brush:php">class Db
{
    public static function factory($type)
    {
        $fileName = 'Db_' . strtolower($type) . '.php';
        if (!file_exists($fileName)) {
            throw new Exception('File not found : ' . $fileName);
        }

        $className = 'Db_' . strtolower($type);

        return new $className;
    }
}</pre>
<p>What this class does now is it allows me to load the relevant database connection class on the fly. If I want a Microsoft SQL connection I would call:</p>
<pre class="brush:php">    $mssql = Db::factory('mssql');</pre>
<p>while for MySQL the command becomes:</p>
<pre class="brush:php">    $mysql = Db::factory('mysql');</pre>
<p>Again since both underlying classes implement the iDatabase interface, I know exactly what to expect as far as methods and functionality is concerned from each class.</p>
<h3>Conclusion</h3>
<p>The Factory Design Pattern is one of the most powerful design patterns. It provides &#8216;decoupling&#8217; i.e. breaks the inherited dependency of a class and its subclasses. It also allows for great flexibility while keeping the same interface for your clients.</p>
<p><a href="http://framework.zend.com">Zend Framework</a> uses the Factory Pattern in <a href="http://framework.zend.com/manual/en/zend.db.adapter.html">Zend_Db</a>. Specifically the example on the site shows:</p>
<pre class="brush:php">// We don't need the following statement because the
// Zend_Db_Adapter_Pdo_Mysql file will be loaded for us by
// the Zend_Db factory method.

// require_once 'Zend/Db/Adapter/Pdo/Mysql.php';

// Automatically load class Zend_Db_Adapter_Pdo_Mysql
// and create an instance of it.
$db = Zend_Db::factory('Pdo_Mysql', array(
          'host'     =&gt; '127.0.0.1',
          'username' =&gt; 'webuser',
          'password' =&gt; 'xxxxxxxx',
          'dbname'   =&gt; 'test'
      ));</pre>
<p>The <a href="http://framework.zend.com/manual/en/zend.db.adapter.html">Zend_Db</a> factory accepts the name of the adapter used for the database connection as the first parameter while the second parameter is an array with connection specific information. With the use of the Factory Pattern, <a href="http://framework.zend.com/manual/en/zend.db.adapter.html">Zend_Db</a> exposes a common interface which allows programmers to connect to a number of databases using the same methods. Should in the future the application needs to access a different database, the impact to the developer is minimal &#8211; in most cases a change to the adapter name (first parameter of the factory class) is all it takes.</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-6325600846885391";
/* www.niden.net Blog 468x60 */
google_ad_slot = "1288968183";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h4  class="related_post_title">Related Posts</h4><ul class="related_post"><li>January 22, 2010 -- <a href="http://www.niden.net/2010/01/design-patterns-singleton-series-how-to/" title="Design Patterns &#8211; Singleton [Series][How-To]">Design Patterns &#8211; Singleton [Series][How-To]</a> (12)</li><li>January 6, 2010 -- <a href="http://www.niden.net/2010/01/design-patterns-series/" title="Design Patterns &#8211; Series [Series][How-To]">Design Patterns &#8211; Series [Series][How-To]</a> (0)</li><li>December 15, 2009 -- <a href="http://www.niden.net/2009/12/url-beautification/" title="URL Beautification [How-To]">URL Beautification [How-To]</a> (0)</li><li>December 11, 2009 -- <a href="http://www.niden.net/2009/12/variables-in-php-ini/" title="Variables in php.ini [How-To]">Variables in php.ini [How-To]</a> (1)</li><li>November 16, 2009 -- <a href="http://www.niden.net/2009/11/flexible-storage-in-mysql/" title="Flexible Storage in MySQL [How-To]">Flexible Storage in MySQL [How-To]</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.niden.net/2010/02/design-patterns-factory-series-how-to/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Design Patterns &#8211; Singleton [Series][How-To]</title>
		<link>http://www.niden.net/2010/01/design-patterns-singleton-series-how-to/</link>
		<comments>http://www.niden.net/2010/01/design-patterns-singleton-series-how-to/#comments</comments>
		<pubDate>Fri, 22 Jan 2010 14:51:22 +0000</pubDate>
		<dc:creator>Nikolaos Dimopoulos</dc:creator>
				<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Series]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://www.niden.net/?p=205</guid>
		<description><![CDATA[A note about these series. It appears that Giorgio Sironi and I had the same idea regarding Design Patterns and blogging about them. He covers the Singleton design pattern thoroughly in his blog post, which is recommended reading. The Problem When I started programming in PHP I was faced with creating a simple database driven [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>A note about these series. It appears that <a href="http://giorgiosironi.blogspot.com">Giorgio Sironi</a> and I had the same idea regarding Design Patterns and blogging about them. He covers the <a href="http://giorgiosironi.blogspot.com/2010/01/practical-php-patterns-singleton.html">Singleton</a> design pattern thoroughly in his blog post, which is recommended reading.</p>
<h3>The Problem</h3>
<p>When I started programming in PHP I was faced with creating a simple database driven web page for a <a href="http://ffff.niden.net">Ferrari Fans Fun club</a>. The page had 5 different sections that each accessed the database to retrieve data. Each section was included in more than one page and only the menu, header and footer were common in all pages.</p>
<p>My first design and implementation was horrible. I still have the files and for the purposes of this blog post I went back and checked on them and I can safely say I am ashamed of that code. But then again we all start from somewhere so that was my start and more importantly I do not program like that any more. The picture below shows how the page was constructed:</p>
<table style="border: 1px solid #4B0082; width: 100%;" border="0">
<tbody>
<tr>
<td style="border: 1px solid #4B0082; text-align: center; font-weight: bold; height: 50px;" colspan="3">Header</td>
</tr>
<tr>
<td style="border: 1px solid #4B0082; text-align: center; font-weight: bold; height: 100px; width: 20%;">Menu</td>
<td style="border: 1px solid #4B0082; text-align: center; font-weight: bold; height: 100px; width: 60%;">Content</td>
<td style="border: 1px solid #4B0082; text-align: center; font-weight: bold; height: 100px; width: 20%;">Additional information</td>
</tr>
<tr>
<td style="border: 1px solid #4B0082; text-align: center; font-weight: bold; height: 50px;" colspan="3">Footer</td>
</tr>
</tbody>
</table>
<p>Each of the sections was a different php script (header.php, menu.php, content.php, footer.php, info.php) and in order to retrieve information from the database for each section I had the following snippet at the top of each script:</p>
<pre class="brush:php">$dbName = 'FFFF';
$dbUser = 'ffff_user';
$dbPass = 'mypassword';
$dbHost = 'localhost';

$conn = mysql_connect($dbHost, $dbUser, $dbPass);
if (!$conn) {
    die(('Cannot connect to the database :' . mysql_error());
}

$db = mysql_select_db($dbName, $conn);
if (!$db) {
    die ('Cannot select the database : ' . mysql_error());
}</pre>
<p>Some might comment on my error handling or the naming of the variables. That is not the problem. The problem is that the snippet of code above was used in <strong>every script file</strong> (all 5 of them). As a result every page load was hitting the database 5 times. Although the intended user base was no more than 100 people, due to this design flaw I had the equivalent of 500 users.</p>
<h3>The first step &#8211; Primitive refactoring</h3>
<p>You might argue that the two files (header, menu) can easily be combined into one (and the same with additional information and footer) and that will save me 3 connections. The layout does not change but now each of the shaded areas represent one script:</p>
<table style="border: 1px solid #4B0082; width: 100%;" border="0">
<tbody>
<tr>
<td style="border: 1px solid #4B0082; background: #DD0000; text-align: center; font-weight: bold; height: 50px;" colspan="3">Header</td>
</tr>
<tr>
<td style="border: 1px solid #4B0082; background: #DD0000; text-align: center; font-weight: bold; height: 100px; width: 20%;">Menu</td>
<td style="border: 1px solid #4B0082; text-align: center; font-weight: bold; height: 100px; width: 60%;">Content</td>
<td style="border: 1px solid #4B0082; background: #00DD00; text-align: center; font-weight: bold; height: 100px; width: 20%;">Additional information</td>
</tr>
<tr>
<td style="border: 1px solid #4B0082; background: #00DD00; text-align: center; font-weight: bold; height: 50px;" colspan="3">Footer</td>
</tr>
</tbody>
</table>
<p>Although this is a good start it is not the solution to the problem. I have effectively reduced the number of hits to 3 per visitor (300 vs 500 before). The goal is to have one connection per visitor.</p>
<h3>One step further &#8211; A global variable</h3>
<p>I need to create the database connection, store it in a global variable, and then let the rest of the scripts access that variable &#8211; and subsequently the database connection &#8211; when needed. The pseudo code is as follows:</p>
<ol>
<li>Load script header.php</li>
<li>Get the database credentials</li>
<li><strong>Create a database connection</strong></li>
<li>Select the database</li>
<li>Display the data</li>
<li>Load script content.php</li>
<li><strong>Get the database connection</strong></li>
<li>Display the data</li>
<li>Load script footer.php</li>
<li><strong>Get the database connection</strong></li>
<li>Display the data</li>
</ol>
<p>I need to ensure that my database connection is initiated at the beginning of every page. The script header.php is the most obvious place:</p>
<pre class="brush:php">$dbName = 'FFFF';
$dbUser = 'ffff_user';
$dbPass = 'mypassword';
$dbHost = 'localhost';

$DBconn = mysql_connect($dbHost, $dbUser, $dbPass);
if (!$DBconn) {
    die(('Cannot connect to the database :' . mysql_error());
}

$db = mysql_select_db($dbName, $DBconn);
if (!$db) {
    die ('Cannot select the database : ' . mysql_error());
}</pre>
<p>In every script thereafter I need to reference the global variable and I can then use it in that script:</p>
<pre class="brush:php">global $DBconn;</pre>
<p>Although this is an &#8220;acceptable&#8221; way of programming, maintaining all the global variables can easily be a nightmare for</p>
<ul>
<li>maintenance</li>
<li>testing</li>
<li>quality control</li>
<li>any part of the code in any script that references this global variable can effectively change that variable</li>
<li>that the code will look &#8220;ugly&#8221; (hey I am proud of the code that I write <img src='http://www.niden.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> )</li>
</ul>
<h3>Design Patterns &#8211; Singleton</h3>
<p>A better approach to solve this problem is to use a design pattern. In this case I will use the Singleton Pattern.</p>
<p>The Singleton pattern is applied to a class which when called will create a database connection if the connection does not exist or pass the connection back to the caller if it has already been instantiated. This way I really do not care where the database credentials will be added and when the connection will be instantiated. The first time that I am calling the class that implements the Singleton pattern will connect to the database and have the connection stored ready to be used. The pseudo code is as follows:</p>
<ol>
<li>Load script header.php</li>
<li>Get the database credentials</li>
<li><strong>Create a database connection</strong></li>
<li>Select the database</li>
<li>Display the data</li>
<li>Load script content.php</li>
<li><strong>Get the database connection</strong></li>
<li>Display the data</li>
<li>Load script footer.php</li>
<li><strong>Get the database connection</strong></li>
<li>Display the data</li>
</ol>
<p>The class that I created is as follows:</p>
<pre class="brush:php">&lt;?php
class Db
{
    private static $_db   = null;
    private static $_conn = null;

    private function __construct()
    {
        // This is where we have the connection parameters
        include_once 'connection.inc.php';

        $this-&gt;_conn = mysql_connect($host, $user, $password);
        if (!$this-&gt;_conn) {
            throw new Exception('Cannot connect to the database :' . mysql_error());
        }

        $db = mysql_select_db($database, $this-&gt;_conn);
        if (!$db) {
            throw new Exception('Cannot select the database : ' . mysql_error());
        }
    }

    private function __destruct()
    {
        mysql_close($this-&gt;_conn);
    }

    // The singleton method
    public static function getInstance()
    {
        if (null === self::$db) {
            self::$_db = new Db($options);
        }

        return self::$_db;
    }

    public function query($sql)
    {
        $_result = mysql_query($sql);

        if (!$_result) {
            throw new Exception('Error in query : ' . mysql_error() . "\n" . $sql);
        }

        $data = array();

        while ($row = mysql_fetch_assoc($_result)) {
            $data[$row['id']] = $row;
        }

        mysql_free_result($_result);

        return $data;
    }
}
?&gt;</pre>
<p>With this class available I really do not care if my database connection code is at the beginning of my scripts or not. Using this class allows me to create the database connection (if it is not established) and persist/reuse it further down the script execution.</p>
<p>The code for my header and menu (see graphic above) becomes:</p>
<pre class="brush:php">    $sql = 'SELECT menu_id, menu_name FROM tbl_menu';
    $menu = Db::getInstance()-&gt;query($sql);</pre>
<p>while the one for the rest of the site is exactly identical sans the query to be executed. The problem is solved (I now have one connection per visitor) and the code seems a lot tidier.</p>
<p>Note that the connection parameters are in a separate file which is accessed during the __construct() method of the class. You can use anything you want to supply these parameters in your class.</p>
<h3>Conclusion</h3>
<p>The Singleton Design Pattern is a blessing in disguise. If the ground work has not been done (i.e. create tests for your code and thoroughly document it) then it is difficult for a new developer coming into a project to understand what is going on, especially when the new developer needs to make alterations and run newly created tests.</p>
<p>A word of caution: If you choose to use this pattern in your application, make sure that everything you do is thoroughly documented and tested. This will make your life a lot easier in the long run and will aid in maintenance.</p>
<h5>Update: Thanks to <a rel="external nofollow" href="http://codeutopia.net/">Jani Hartikainen</a> for pointing out an error in the code.</h5>
<p><script type="text/javascript"><!--
google_ad_client = "pub-6325600846885391";
/* www.niden.net Blog 468x60 */
google_ad_slot = "1288968183";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h4  class="related_post_title">Related Posts</h4><ul class="related_post"><li>February 2, 2010 -- <a href="http://www.niden.net/2010/02/design-patterns-factory-series-how-to/" title="Design Patterns – Factory [Series][How-To]">Design Patterns – Factory [Series][How-To]</a> (0)</li><li>January 6, 2010 -- <a href="http://www.niden.net/2010/01/design-patterns-series/" title="Design Patterns &#8211; Series [Series][How-To]">Design Patterns &#8211; Series [Series][How-To]</a> (0)</li><li>December 15, 2009 -- <a href="http://www.niden.net/2009/12/url-beautification/" title="URL Beautification [How-To]">URL Beautification [How-To]</a> (0)</li><li>December 11, 2009 -- <a href="http://www.niden.net/2009/12/variables-in-php-ini/" title="Variables in php.ini [How-To]">Variables in php.ini [How-To]</a> (1)</li><li>November 16, 2009 -- <a href="http://www.niden.net/2009/11/flexible-storage-in-mysql/" title="Flexible Storage in MySQL [How-To]">Flexible Storage in MySQL [How-To]</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.niden.net/2010/01/design-patterns-singleton-series-how-to/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Create a SSL Certificate (Linux) [How-To]</title>
		<link>http://www.niden.net/2010/01/how-to-create-a-ssl-certificate-linux/</link>
		<comments>http://www.niden.net/2010/01/how-to-create-a-ssl-certificate-linux/#comments</comments>
		<pubDate>Sun, 10 Jan 2010 17:24:07 +0000</pubDate>
		<dc:creator>Nikolaos Dimopoulos</dc:creator>
				<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[SSL]]></category>

		<guid isPermaLink="false">http://www.niden.net/?p=268</guid>
		<description><![CDATA[There are times that I want to set up a secure communication with the server I am working on. This might be because I want to run phpMyAdmin over SSL (I do not like unencrypted communications over the Internet), install a certificate for an eShop for a client or just for my personal use. The [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>There are times that I want to set up a secure communication with the server I am working on. This might be because I want to run phpMyAdmin over SSL (I do not like unencrypted communications over the Internet), install a certificate for an eShop for a client or just for my personal use.</p>
<p>The first time I did this, I had to research on the Internet and after a bit of a trial and error I managed to get everything working. However if you do not do something on a regular basis you will forget. I am no exception to this rule hence this post to allow me to remember what I did and hopefully help you too.</p>
<h4>Prerequisites:</h4>
<p>This how-to assumes that you are running Gentoo, however these instructions can easily be applied to any other Linux distribution.</p>
<p>I need to check if <a href="http://www.openssl.org/">openssl</a> is installed:</p>
<pre><span style="color: #800000;">vanadium </span><span style="color: #333399;">~ #</span> emerge --pretend dev-libs/openssl

<span style="color: #008000;">These are the packages that would be merged, in order:</span>

Calculating dependencies... done!
[<span style="color: #00ff00;">ebuild</span>   <span style="color: #ffff00;">R</span>   ] <span style="color: #00ff00;">dev-libs/openssl-0.9.8l-r2</span></pre>
<p>If you do not see the [R] next to the package (and you see a N for instance) that means that you need to install the package. Issuing:</p>
<pre><span style="color: #800000;">vanadium </span> <span style="color: #333399;">~ #</span> emerge --verbose dev-libs/openssl</pre>
<p>will do the trick.</p>
<h4>Generate the Private Key</h4>
<p>I like to generate keys with a lot of bits. All of my certificates have 4096 bits. This is a personal preference and it does not hurt to keep that value. Your host or Signing Authority (like GoDaddy, VeriSign, Thawte etc.) might ask you in their instructions to generate one with 2048 bits so don&#8217;t be alarmed there.</p>
<p>Creating the RSA private key with 4096 bits using Triple-DES:</p>
<pre><span style="color: #800000;">vanadium</span> <span style="color: #333399;">~ #</span> openssl genrsa -des3 -out /root/vanadium.niden.net.locked.key 4096
Generating RSA private key, 4096 bit long modulus
.............................................................++
...........++
e is 65537 (0x10001)
Enter pass phrase for /root/vanadium.niden.net.locked.key:
Verifying - Enter pass phrase for /root/vanadium.niden.net.locked.key:</pre>
<h4>Remove the passphrase from the Private Key</h4>
<p>The key that was created earlier has a passphrase. Although this is good, it does have a side effect that any web server administrator does not like &#8211; the passphrase itself. Once the certificate is installed using the key (with the passphrase), every time that Apache is restarted, it will prompt the operator for the passphrase. This can be very inconvenient if your web server reboots in the middle of the night. Since Apache will be waiting for the passphrase, your site will be inaccessible.</p>
<p>To avoid this inconvenience, I am removing the passphrase from the key. If you noticed the key that I have created above has the &#8216;locked&#8217; phrase in its name. The reason is that I know that that particular key has the passphrase on it. I first need to copy the key and then remove the passphrase:</p>
<pre><span style="color: #800000;">vanadium</span> <span style="color: #333399;">~ #</span> cp -v vanadium.niden.net.locked.key vanadium.niden.net.key
`vanadium.niden.net.locked.key' -&gt; `vanadium.niden.net.key'
<span style="color: #800000;">vanadium</span> <span style="color: #333399;">~ #</span> openssl rsa -in vanadium.niden.net.locked.key -out vanadium.niden.net.key
Enter pass phrase for vanadium.niden.net.locked.key:
writing RSA key</pre>
<h4>Generate the Certificate Signing Request (CSR)</h4>
<p>The purpose of the CSR is to be sent to one of the Certificate Authorities (GoDaddy, VeriSign, Thawte etc.) for verification. Alternatively I can self-sign the CSR (see below).</p>
<p>Upon generation of this CSR I am asked about particular pieces of information to be incorporated in the CSR. The most important piece of information that I need to ensure that is correct is the &#8220;<strong>Common Name</strong>&#8220;. The answer to that question has to be the name of my web server &#8211; vanadium.niden.net in my case.</p>
<p><strong><em>NOTE</em></strong>: I am using the key without the passphrase.</p>
<p>The command to generate the CSR is as follows:</p>
<pre class="bash:brush"><span style="color: #800000;">vanadium</span> <span style="color: #333399;">~ #</span> openssl req -new -key vanadium.niden.net.key -out vanadium.niden.net.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:Virginia
Locality Name (eg, city) []:Arlington
Organization Name (eg, company) [Internet Widgits Pty Ltd]:niden.net
Organizational Unit Name (eg, section) []:IT
Common Name (eg, YOUR name) []:vanadium.niden.net
Email Address []:domains@niden.net

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:</pre>
<p>Once this step is completed, I open the CSR file with a text editor, copy the contents and paste them in the relevant field of the Certification Authority (in my case GoDaddy), so that they can verify the CSR and issue the certificate.</p>
<p>If however this is a development box or you do not want your certificate signed by a Certification Authority, you can check the section below on how to generate a self-signed certificate.</p>
<h4>Generating a Self-Signed Certificate</h4>
<p>Generating a certificate valid for 365 days, I need to issue the following command:</p>
<p>At this point you will need to generate a self-signed certificate because you either don&#8217;t plan on having your certificate signed by a CA, or you wish to test your new SSL implementation while the CA is signing your certificate. This temporary certificate will generate an error in the client browser to the effect that the signing certificate authority is unknown and not trusted.<br />
To generate a temporary certificate which is good for 365 days, issue the following command:</p>
<pre><span style="color: #800000;">vanadium</span> <span style="color: #333399;">~ #</span> openssl x509 -req -days 365 -in vanadium.niden.net.csr -signkey vanadium.niden.net.key -out vanadium.niden.net.crt
Signature ok
subject=/C=US/ST=Virginia/L=Arlington/O=niden.net/OU=IT/CN=vanadium.niden.net/emailAddress=domains@niden.net
Getting Private key</pre>
<h4>Installation</h4>
<p>For my system, the certificates are kept under /etc/apache2/ssl/ so I am going to copy them there (your need to adjust the instructions below to suit your system/installation):</p>
<pre><span style="color: #800000;">vanadium</span> <span style="color: #333399;">~ #</span> cp -v vanadium.niden.net.key /etc/apache2/ssl/
<span style="color: #800000;">vanadium</span> <span style="color: #333399;">~ #</span> cp -v vanadium.niden.net.crt /etc/apache2/ssl/</pre>
<p>I also need to open the relevant file to enable the certificate</p>
<pre><span style="color: #800000;">vanadium</span> <span style="color: #333399;">~ #</span> nano -w /etc/apache2/vhosts.d/00_default_ssl_vhost.conf</pre>
<p>In that file I need to change the following directives:</p>
<pre>SSLCertificateFile /etc/ssl/apache2/vanadium.niden.net.crt
SSLCertificateKeyFile /etc/ssl/apache2/vanadium.niden.net.key</pre>
<p>If my certificate was issued by a Certificate Authority, the files that I have received have the CA certificate file. I can enable it in the following line:</p>
<pre>SSLCACertificateFile /etc/ssl/apache2/vanadium.niden.net.ca-bundle.crt</pre>
<h4>Restarting Apache</h4>
<pre><span style="color: #800000;">vanadium</span> <span style="color: #333399;">~ #</span> /etc/init.d/apache2 restart
vanadium ~ # /etc/init.d/apache2 restart
 * Stopping apache2 ...                              [ ok ]
 * Starting apache2 ...                              [ ok ]</pre>
<p>Navigating to <strong>https://vanadium.niden.net</strong> should tell me if what I did was successful or not. If your browser (Google Chrome in my case) gives you a bright red screen with all sorts of warnings, that means that</p>
<ul>
<li>either you self signed the certificate &#8211; in which case it complains about the certificate not being signed by a Certificate Authority or</li>
<li>you made a mistake and the Common Name in the certificate is not the same as the host name.</li>
</ul>
<p>Both these errors are easy to fix.</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-6325600846885391";
/* www.niden.net Blog 468x60 */
google_ad_slot = "1288968183";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h4  class="related_post_title">Related Posts</h4><ul class="related_post"><li>August 21, 2010 -- <a href="http://www.niden.net/2010/08/how-to-create-an-inexpensive-hourly-remote-backup/" title="Create an inexpensive hourly remote backup [How-To]">Create an inexpensive hourly remote backup [How-To]</a> (3)</li><li>December 10, 2009 -- <a href="http://www.niden.net/2009/12/faster-rsync-and-emerge-in-gentoo/" title="Faster rsync and emerge in Gentoo [How-To]">Faster rsync and emerge in Gentoo [How-To]</a> (0)</li><li>November 16, 2009 -- <a href="http://www.niden.net/2009/11/gentoo-stage-1-installation/" title="Gentoo Stage 1 Installation [How-To]">Gentoo Stage 1 Installation [How-To]</a> (1)</li><li>August 1, 2010 -- <a href="http://www.niden.net/2010/08/subversion-backup-how-to/" title="Subversion Backup [How-To]">Subversion Backup [How-To]</a> (5)</li><li>November 24, 2009 -- <a href="http://www.niden.net/2009/11/chromium-os-part-3/" title="Chromium OS Part 3 [How-To]">Chromium OS Part 3 [How-To]</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.niden.net/2010/01/how-to-create-a-ssl-certificate-linux/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Design Patterns &#8211; Series [Series][How-To]</title>
		<link>http://www.niden.net/2010/01/design-patterns-series/</link>
		<comments>http://www.niden.net/2010/01/design-patterns-series/#comments</comments>
		<pubDate>Wed, 06 Jan 2010 19:52:47 +0000</pubDate>
		<dc:creator>Nikolaos Dimopoulos</dc:creator>
				<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Series]]></category>

		<guid isPermaLink="false">http://www.niden.net/?p=202</guid>
		<description><![CDATA[A lot of developers – including myself – have at some point in their programming careers found themselves repeating a task that they have completed for a previous project or for a previous part of the same project. This problem of repeating code is solved by design patterns. A design pattern is the way that [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>A lot of developers – including myself – have at some point in their programming careers found themselves repeating a task that they have completed for a previous project or for a previous part of the same project.</p>
<p>This problem of repeating code is solved by design patterns. A design pattern is the way that the code must be structured so that the problem at hand can be solved. The characteristics of design patterns are:</p>
<ul>
<li><strong>Name</strong> – it lets other programmers know what this pattern does.</li>
<li><strong>Problem</strong> – where the pattern can be applied</li>
<li><strong>Solution</strong> – how this pattern is implemented</li>
</ul>
<p>In the course of the next few weeks, I will publish a series of blog posts, where  I will try to present you with some common design patterns and how I have understood their use. Most books and online materials concentrate on just presenting the issue at hand and do not focus on how we ended up there. In these blog post series I will try to show you what I found along the way and how I solved each problem in turn.</p>
<p>As usual comments are more than welcome.</p>
<p>The design patterns I will discuss in posts of these series are as:</p>
<ol>
<li><a href="http://www.niden.net/2010/01/design-patterns-singleton-series-how-to/">Singleton Pattern</a></li>
<li><a href="http://www.niden.net/2010/01/design-patterns-factory-series-how-to/">Factory Pattern</a></li>
<li>Registry Pattern</li>
<li>Decorator Pattern</li>
<li>Adapter Pattern</li>
<li>Iterator Pattern</li>
<li>Strategy Pattern</li>
<li>Active Record Pattern</li>
<li>Value Object Pattern</li>
<li>Model View Controller Pattern</li>
<li>MockObject Pattern</li>
<li>Observer Pattern</li>
<li>Proxy Pattern</li>
<li>Table Data Gateway Pattern</li>
<li>Data Mapper Pattern</li>
</ol>
<p>You can check this blog every week, <a href="http://feeds.feedburner.com/nikosdimopoulos">subscribe to the RSS feed</a>, <a href="http://twitter.com/nikosdimopoulos">follow me on Twitter</a> or <a href="http://www.google.com/profiles/nikos.dimopoulos.usa">follow my Google Reader</a> (or all of the above).</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-6325600846885391";
/* www.niden.net Blog 468x60 */
google_ad_slot = "1288968183";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h4  class="related_post_title">Related Posts</h4><ul class="related_post"><li>February 2, 2010 -- <a href="http://www.niden.net/2010/02/design-patterns-factory-series-how-to/" title="Design Patterns – Factory [Series][How-To]">Design Patterns – Factory [Series][How-To]</a> (0)</li><li>January 22, 2010 -- <a href="http://www.niden.net/2010/01/design-patterns-singleton-series-how-to/" title="Design Patterns &#8211; Singleton [Series][How-To]">Design Patterns &#8211; Singleton [Series][How-To]</a> (12)</li><li>December 15, 2009 -- <a href="http://www.niden.net/2009/12/url-beautification/" title="URL Beautification [How-To]">URL Beautification [How-To]</a> (0)</li><li>December 11, 2009 -- <a href="http://www.niden.net/2009/12/variables-in-php-ini/" title="Variables in php.ini [How-To]">Variables in php.ini [How-To]</a> (1)</li><li>December 2, 2009 -- <a href="http://www.niden.net/2009/12/the-world-with-angular-part-3/" title="The world with &lt;angular/&gt; Part 3 [Review][How-To]">The world with &lt;angular/&gt; Part 3 [Review][How-To]</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.niden.net/2010/01/design-patterns-series/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>URL Beautification [How-To]</title>
		<link>http://www.niden.net/2009/12/url-beautification/</link>
		<comments>http://www.niden.net/2009/12/url-beautification/#comments</comments>
		<pubDate>Wed, 16 Dec 2009 02:35:09 +0000</pubDate>
		<dc:creator>Nikolaos Dimopoulos</dc:creator>
				<category><![CDATA[How-To]]></category>
		<category><![CDATA[Input]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[URL]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[mod_rewrite]]></category>

		<guid isPermaLink="false">http://www.niden.net/?p=237</guid>
		<description><![CDATA[The last few years I have been using Quicken to manage the home bank accounts and spending. My wife never had any problems with me doing so and it helps us manage our cash flow better. Of course like every couple we buy things that we need and always provision a small amount of money [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>The last few years I have been using Quicken to manage the home bank accounts and spending. My wife never had any problems with me doing so and it helps us manage our cash flow better. Of course like every couple we buy things that we need and always provision a small amount of money for personal expenses.</p>
<p>Some time ago when downloading the transactions from our bank, I noticed a rather odd name coming in for a very small charge (less than 20 dollars). So I asked my wife what that shop is. Her response was &#8220;<em>Beautification</em>&#8220;. My reply was &#8220;<em>What do you mean? You don&#8217;t need anything &#8211; you are gorgeous as is&#8230;</em>&#8220;. Although this did earn me brownie points it also infuriated my wife since she was thinking I was auditing her. My sole purpose of that question was to assess the category of the expense and move on. I was not interested the least about the particulars of the expense. I got my reply &#8211; a detailed one &#8211; as to what the item was for (makeup really) and once my wife finished I explained to her that all this explanation was unecessary and all I needed was &#8220;<em>Personal Care</em>&#8220;&#8230;. The night ended in laughter as you can imagine and since then we always refer as &#8220;<em>Beautification</em>&#8221; when we pass the makeup area in the grocery store.</p>
<p>The purpose of this post is not to try to make you go buy makeup. It is however a post that can show you how you can make your application&#8217;s behavior as far as URLs are concerned &#8220;prettier&#8221;.</p>
<p>&#8220;<em>Beautification</em>&#8221; in URLs is also known as Pretty URLs in some cases. It is a method where mod_rewrite is used to make a URL look easier to remember. Although this process started in an attempt to increase SEO and make a site&#8217;s URLs easier to index/follow, it has now become a must for every site that wants to create awareness and make people remember as much as possible so that they can revisit. WordPress (this blog&#8217;s blogging software) as well as other blogging software use this methodology to ensure that the posts are easily indexed and remembered (see the URL of this post and the title of this post).</p>
<h3>First Step</h3>
<p>Instead of rewriting my whole application to have beautiful and easy to remember URLs, I started with changing the way I processed parameters. Imagine the scenario where I have a site with various pages and one script that processes everything. My URL could be something like:</p>
<pre class="brush:php">..../site.php?page=contact-us
..../site.php?page=about</pre>
<p>Following discussions with other developers and reading the web the URL was beautified as:</p>
<pre class="brush:php">..../site.php?page/contact-us
..../site.php?page/about</pre>
<p>This effectively is one parameter, so in my bootstrap I have the following snippet:</p>
<pre class="brush:php">$getData  = array();
$params = explode('/',$_SERVER['QUERY_STRING']);
$params[] = '';
$paramsLength = sizeof($params);
for ($counter = 0; $counter &lt; $paramsLength; $counter++) {
    $getData[$params[$counter]] = (isset($params[$counter + 1])) ? $params[$counter + 1] : '';
}

unset($_GET);</pre>
<p>The $getData array contains the parameters that have been passed and allows all search engines to index the URL a lot easier since this is considered to be one parameter.</p>
<p>Please note that I am not going to expand on security here. In my production code there are multiple checks on the variables passed so as to ensure that there are no SQL injection vulnerabilities.</p>
<h3>A better approach with .htaccess</h3>
<p>In order to make the URL look a lot more &#8220;beautified&#8221;, I need to remove the script name and the questionmark of the query string. So my URL can easily be like:</p>
<pre class="brush:php">..../page/contact-us
..../page/about</pre>
<p>To achieve this, I need (in Apache) <strong><a href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html">mod_rewrite</a></strong> enabled and a couple of directives in httpd.conf</p>
<pre>Options +FollowSymLinks
RewriteEngine On</pre>
<p>If your configuration is on a virtual host, you can add these directives in your vhosts file.</p>
<p>The .htaccess file that I have in the root folder of my site has the following directives:</p>
<pre>Options +FollowSymLinks
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule .* site.php [L]</pre>
<p>What the above file does is pass everything in the site.php script. The processing now falls in the site.php script. At the top of the script I have:</p>
<pre class="brush:php">&lt;?php

// This is where we get all the parameters
$params = $_SERVER['REQUEST_URI'];

if (substr('/', $params) &gt; 0) {
    switch ($params) {
        case '/page/contact-us':
            include 'contact_us.php';
            break;
        case '/page/about':
            include 'about.php';
            break;
        default:
            include 'filenotfound.php';
            break;
    }

// No parameters passed - display something default
} else {
   include 'filenotfound.php';
}</pre>
<p>From here on the possibilities are endless. I can add more logic to the rewrite rules so that everything ends in .html for instance, making search engines think that they are visiting unique html pages. Discussion forum software uses this technique to make their content easily searchable. For instance a URL like:</p>
<pre class="brush:php">/showpost.php?p=557799</pre>
<p>can be shown as:</p>
<pre class="brush:php">/show/post/post/557799</pre>
<p>or</p>
<pre class="brush:php">/show/post/post-557799.html</pre>
<p>Something like the above can be achieved with the following rule in .htaccess:</p>
<pre class="brush:php">Options +FollowSymLinks
RewriteEngine On
RewriteRule ^post-([0-9]+)+\.html$ /showpost.php?p=$1 [NC,L]</pre>
<h3>Zend Framework</h3>
<p>If I want to push the envelope further I will need to use <a href="http://framework.zend.com">Zend Framework</a> to do all this effortlessly. Zend Framework&#8217;s <a href="http://framework.zend.com/manual/en/zend.controller.html">front controller</a> provides amazing flexibility in terms of how my application URLs can be displayed on the web.</p>
<p><a href="http://framework.zend.com/manual/en/zend.controller.router.html#zend.controller.router.routes.standard">Zend_Controller_Router_Route</a>, <a href="http://framework.zend.com/manual/en/zend.controller.router.html#zend.controller.router.routes.static">Zend_Controller_Router_Route_Static</a> and <a href="http://framework.zend.com/manual/en/zend.controller.router.html#zend.controller.router.default-routes">Zend_Controller_Router_Rewrite</a> are some of the types of routes available in the front controller. Using a configuration file or issuing relevant directives in the bootstrap file are options that I can use to manipulate my application&#8217;s URLs.</p>
<p>By default the front controller uses the controller/action scheme but I can easily change this using a router and adding that router to my controller.</p>
<pre class="brush:php">$router = $frontController-&gt;getRouter();

$router-&gt;addRoute(
    'post',
    new Zend_Controller_Router_Route(
        'post/:post',
        array('controller' =&gt; 'post',
              'action' =&gt; 'show'))
    );</pre>
<p>This is a small example on how a simple controller/action sequence can still work as expected and the resulting URL is &#8220;beautified&#8221;.</p>
<h4>Final thoughts</h4>
<p>Having easy to remember URLs in an application is a must. It will not only help search engines crawl your site easier &#8211; thus making your site more easily discoverable &#8211; but it will also help your users remember key areas of your site.</p>
<p><a href="http://framework.zend.com">Zend Framework</a> is by far one of the best solutions available, since it introduces a small learning curve in terms of routing and mod_rewrite while providing pretty URLs. However, for more a complicated rewriting scheme your application might need a very sophisticated <a href="http://httpd.apache.org/docs/2.0/howto/htaccess.html">.htaccess</a> file.</p>
<h4  class="related_post_title">Related Posts</h4><ul class="related_post"><li>February 2, 2010 -- <a href="http://www.niden.net/2010/02/design-patterns-factory-series-how-to/" title="Design Patterns – Factory [Series][How-To]">Design Patterns – Factory [Series][How-To]</a> (0)</li><li>January 22, 2010 -- <a href="http://www.niden.net/2010/01/design-patterns-singleton-series-how-to/" title="Design Patterns &#8211; Singleton [Series][How-To]">Design Patterns &#8211; Singleton [Series][How-To]</a> (12)</li><li>December 11, 2009 -- <a href="http://www.niden.net/2009/12/variables-in-php-ini/" title="Variables in php.ini [How-To]">Variables in php.ini [How-To]</a> (1)</li><li>January 6, 2010 -- <a href="http://www.niden.net/2010/01/design-patterns-series/" title="Design Patterns &#8211; Series [Series][How-To]">Design Patterns &#8211; Series [Series][How-To]</a> (0)</li><li>December 2, 2009 -- <a href="http://www.niden.net/2009/12/the-world-with-angular-part-3/" title="The world with &lt;angular/&gt; Part 3 [Review][How-To]">The world with &lt;angular/&gt; Part 3 [Review][How-To]</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.niden.net/2009/12/url-beautification/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Variables in php.ini [How-To]</title>
		<link>http://www.niden.net/2009/12/variables-in-php-ini/</link>
		<comments>http://www.niden.net/2009/12/variables-in-php-ini/#comments</comments>
		<pubDate>Fri, 11 Dec 2009 16:28:45 +0000</pubDate>
		<dc:creator>Nikolaos Dimopoulos</dc:creator>
				<category><![CDATA[How-To]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://www.niden.net/?p=225</guid>
		<description><![CDATA[In my workplace we have been using Zend Framework for more than a year primarily as a glue framework. We have managed to integrate a lot of components from the framework to suit our needs and slowly we are moving towards the full MVC pattern. In the meantime our own framework, or collection of code [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>In my workplace we have been using <a href="http://framework.zend.com">Zend Framework</a> for more than a year primarily as a glue framework. We have managed to integrate a lot of components from the framework to suit our needs and slowly we are moving towards the full MVC pattern.</p>
<p>In the meantime our own framework, or collection of code if you prefer, is slowly evolving with every new project. New classes are added while others are enhanced more to provide more flexible input/output. Add to that the continuous evolution of <a href="http://framework.zend.com">Zend Framework</a> and we are faced with at least one version of our own codebase per project.</p>
<p>Lately we have been following a more <a href="http://www.niden.net/2009/11/test-driven-development/">Test Driven Development</a> approach, where we create tests for every component we create or alter. After all this is the purpose of <a href="http://www.niden.net/2009/11/test-driven-development/">TDD</a> &#8211; to make sure that your code has 100% coverage and that it works!</p>
<p>The same thing applies when a new version of Zend Framework is released. We download the latest version on the development boxes and run our tests against it. If something has changed and/or is broken we just fix it and our framework is ready for the next project.</p>
<p>Following this approach, the bulk of our projects are running the latest code (Zend Framework and our own framework). There are however a number of projects that we need to run against an older version of Zend Framework. The reasons for not are &#8220;<em>not enough money for updating</em>&#8220;, &#8220;<em>not enough time</em>&#8220;, &#8220;<em>it works so don&#8217;t tinker with it</em>&#8221; to name a few.</p>
<p>So how do we deal with the issue of having different versions of Zend Framework on our servers and including the correct version to the relevant project? The solution that we use is variables in php.ini.</p>
<p>For starters we have a network share mounted on all of our development servers (the ones that are in house). This share we call it /resources. In there we have all the needed Zend Framework versions i.e.:</p>
<pre class="brush:bash">gemini ~ # ls -la /resources/ZendFramework/
total 0
drwxrwxr-x 8 webuser webdev 192 Nov  5 05:48 .
drwxr-xr-x 7 webuser webdev 168 Jul 17 10:55 ..
drwxrwxr-x 3 webuser webdev  72 Jun 23 13:48 1.0.3
drwxrwxr-x 5 webuser webdev 216 Apr 21  2009 1.5.2
drwxrwxr-x 7 webuser webdev 280 Apr 21  2009 1.6.2
drwxrwxr-x 8 webuser webdev 304 Apr 21  2009 1.7.8
drwxrwxr-x 8 webuser webdev 296 Jun  8  2009 1.8.3
drwxrwxr-x 8 webuser webdev 296 Oct 26 12:52 1.9.5</pre>
<p>Since this is a network share, all we do is update one location and all servers have access to the same pool of files.</p>
<p>We also modify the php.ini file of each server, adding the following directives at the end of the file:</p>
<pre>[ZendFramework]
ZF_LATEST="/resources/ZendFramework/1.9.5/library"
ZF_1_9_5="/resources/ZendFramework/1.9.5/library"
ZF_1_8_3="/resources/ZendFramework/1.8.3/library"
ZF_1_7_8="/resources/ZendFramework/1.7.8/library"
ZF_1_6_2="/resources/ZendFramework/1.6.2/library"
ZF_1_5_2="/resources/ZendFramework/1.5.2/library"
ZF_1_0_3="/resources/ZendFramework/1.0.3/library"</pre>
<p>Restarting apache gives us access to those variables using the <em>get_cfg_var</em> PHP function. So in our bootstrap file (called init.php) we have the following:</p>
<pre class="brush:php">$zfPath = get_cfg_var('ZF_1_9_5');

$root = dirname(__FILE__);

set_include_path($zfPath         . PATH_SEPARATOR .
                       $root    . '/lib' . PATH_SEPARATOR .
                       $root            . PATH_SEPARATOR .
                       get_include_path());</pre>
<p>Changing to a different version of the Zend Framework can be as easy as changing the path of the ZF_* directive in the php.ini file (and restarting Apache) or by changing the variable we need to use in the init.php file of each project.</p>
<p>This approach allows us to keep our <em>include_path</em> free from any Zend Framework paths since the server has projects that use different versions of the Zend Framework as well as ours. It also helps us in testing, since we can easily check whether a particular project works as expected in a newer or older version of each framework.</p>
<p>We opted out from using constants inside .htaccess files, due to the fact that we have many projects and this would have meant that we had to change every .htaccess file, should we wanted to change the version of Zend Framework used.</p>
<p><a href="http://php.net/manual/en/ini.core.php">php.ini</a> has a lot of directives that can prove useful for the PHP developer. Extending those directives to each project or collection of projects can save you time and headaches.</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-6325600846885391";
/* www.niden.net Blog 468x60 */
google_ad_slot = "1288968183";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h4  class="related_post_title">Related Posts</h4><ul class="related_post"><li>February 2, 2010 -- <a href="http://www.niden.net/2010/02/design-patterns-factory-series-how-to/" title="Design Patterns – Factory [Series][How-To]">Design Patterns – Factory [Series][How-To]</a> (0)</li><li>January 22, 2010 -- <a href="http://www.niden.net/2010/01/design-patterns-singleton-series-how-to/" title="Design Patterns &#8211; Singleton [Series][How-To]">Design Patterns &#8211; Singleton [Series][How-To]</a> (12)</li><li>December 15, 2009 -- <a href="http://www.niden.net/2009/12/url-beautification/" title="URL Beautification [How-To]">URL Beautification [How-To]</a> (0)</li><li>January 6, 2010 -- <a href="http://www.niden.net/2010/01/design-patterns-series/" title="Design Patterns &#8211; Series [Series][How-To]">Design Patterns &#8211; Series [Series][How-To]</a> (0)</li><li>December 2, 2009 -- <a href="http://www.niden.net/2009/12/the-world-with-angular-part-3/" title="The world with &lt;angular/&gt; Part 3 [Review][How-To]">The world with &lt;angular/&gt; Part 3 [Review][How-To]</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.niden.net/2009/12/variables-in-php-ini/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Faster rsync and emerge in Gentoo [How-To]</title>
		<link>http://www.niden.net/2009/12/faster-rsync-and-emerge-in-gentoo/</link>
		<comments>http://www.niden.net/2009/12/faster-rsync-and-emerge-in-gentoo/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 17:24:51 +0000</pubDate>
		<dc:creator>Nikolaos Dimopoulos</dc:creator>
				<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[Installation]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[http-replicator]]></category>
		<category><![CDATA[rsync]]></category>

		<guid isPermaLink="false">http://www.niden.net/?p=211</guid>
		<description><![CDATA[Recently I have started setting up a cluster of 7 Gentoo boxes for a project I am working on. The problem with boxes coming right out of the setup process of a hosting company is that they do not contain the packages that you need. Therefore you need to setup your USE flags and emerge [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Recently I have started setting up a cluster of 7 Gentoo boxes for a project I am working on. The problem with boxes coming right out of the setup process of a hosting company is that they do not contain the packages that you need. Therefore you need to setup your USE flags and emerge the packages you require as per the role of every box.</p>
<p>I have implemented the following procedure many times in my local networks (since I have more than one Gentoo boxes) and have also implemented the same process at work (we run 3 Gentoo boxes).</p>
<p>The way to speed up rsync and emerge is to run a local rsync mirror and to use http-replicator. This will not make the packages compile faster but what it will do is reduce the resource usage (downloads in particular) of your network since each package will be downloaded only one time and reduce the time you have to wait for each package to be downloaded. The same applies with the rsync.</p>
<p>My network has as I said 7 boxes. 5 of them are going to be used as web servers so effectively they have the same USE flags and 2 as database servers. For the purposes of this tutorial I will name the web servers ws1, ws2, ws3, ws4, ws5 and the database servers db1, db2. The ws1 box will be used as the local rsync mirror and will run http-replicator.</p>
<p>I am going to set up the /etc/hosts file on each machine so that the local network is resolved in each box and no hits to the DNS are required. So for my network I have:</p>
<pre>10.13.18.101  ws1
10.13.18.102  ws2
10.13.18.103  ws3
10.13.18.104  ws4
10.13.18.105  ws5
10.13.18.201  db1
10.13.18.202  db2</pre>
<p>Modify the above to your specific setup needs.</p>
<h3>Setting up a local rsync</h3>
<h4>Server setup (ws1)</h4>
<p>There is a really good tutorial can be found in the <a href="http://www.gentoo.org/doc/en/rsync.xml">Gentoo Documentation</a> but here is the short version:</p>
<p>The ws1 box already has the rsync package in there. All I need to do is start the daemon. Some configuration is necessary before I start the service:</p>
<pre class="brush:bash">nano -w /etc/rsyncd.conf</pre>
<p>and what I should have in there is:</p>
<pre class="brush:bash"># Restrict the number of connections
max connections = 5
# Important!! Always use chroot
use chroot = yes
# Just in case you are allowed only read only access
read only = yes
# The user has no privileges
uid = nobody
gid = nobody
# Recommended: Restrict via IP (subnets or just IP addresses)
hosts allow = 10.13.18.0/24
# Everyone else denied
hosts deny  = *

# The local portage
[niden-gentoo-portage]
path = /usr/portage
comment = niden.net Gentoo Portage tree
exclude = /distfiles /packages</pre>
<p>That&#8217;s it. Now I add the service to the default runlevel and start the service</p>
<pre class="brush:bash">rc-update add rsyncd default
/etc/init.d/rsyncd start</pre>
<p>NOTE: If you have a firewall using iptables, you will need to add the following rule:</p>
<pre class="brush:bash"># RSYNC
-A INPUT --protocol tcp --source 10.13.18.0/24 --match state --state NEW --destination-port 873 --jump ACCEPT</pre>
<h4>Client setup</h4>
<p>In my clients I need to edit the /etc/make.conf file and change the SYNC directive to:</p>
<pre class="brush:bash">SYNC="rsync://ws1/niden-gentoo-portage"</pre>
<p>or I can use the IP address:</p>
<pre class="brush:bash">SYNC="rsync://10.13.18.101/niden-gentoo-portage"</pre>
<p>Note that the path used in the SYNC command is what I have specified as a section in the rsyncd.conf file (niden-gentoo-portage in my setup). This path can be anything you like.</p>
<h4>Testing</h4>
<p>I have already run</p>
<pre class="brush:bash">emerge --sync</pre>
<p>in the ws1 box, so all I need to do now is run it on my clients. Once I run it I can see the following (at the top of the listing):</p>
<pre>emerge --sync
&gt;&gt;&gt; Starting rsync with rsync://10.13.18.101/niden-gentoo-portage...
receiving incremental file list
......</pre>
<p>So everything works as I expect it.</p>
<h3>Setting up http-replicator</h3>
<p>http-replicator is a proxy server. When a machine (the local or a remote) requests a package, http-replicator checks its cache and if the file is there, it passes it to the requesting machine. If the file doesn&#8217;t exist though, http-replicator downloads it from a mirror and then passes it to the requesting machine. The file is then kept in http-replicator&#8217;s cache for future requests. This way I save on resources by downloading once and serving many times locally.</p>
<p>Although this might not seem as a &#8216;pure speedup&#8217; it will make your installations and updates faster since the download factor will be reduced to a bare minimum. Waiting for packages like mysql, Gnome or others to be downloaded does take a long time. Multiply that time with the number of machines you have on your network and you can see the benefits of having a setup like this.</p>
<h4>Server setup (ws1)</h4>
<p>First of all I need to emerge the package</p>
<pre class="brush:bash">emerge http-replicator</pre>
<p>Once everything is done I need to change the configuration file to suit my needs:</p>
<pre class="brush:bash">nano -w /etc/conf.d/http-replicator</pre>
<p>and the file should have:</p>
<pre>GENERAL_OPTS="--dir /var/cache/http-replicator"
GENERAL_OPTS="$GENERAL_OPTS --user portage"
DAEMON_OPTS="$GENERAL_OPTS"
DAEMON_OPTS="$DAEMON_OPTS --alias /usr/portage/packages/All:All"
DAEMON_OPTS="$DAEMON_OPTS --log /var/log/http-replicator.log"
DAEMON_OPTS="$DAEMON_OPTS --ip 10.13.18.*"
## The proxy port on which the server listens for http requests:
DAEMON_OPTS="$DAEMON_OPTS --port 8080"</pre>
<p>The last line with the &#8211;port parameter specifies the port that the http-replicator will listen to. You can change it to whatever you want. Also the &#8211;ip parameter restricts who is allowed to connect to this proxy server. I have allowed my whole internal network; change it to suit your needs. Lastly the &#8211;dir option is where the cached data is stored. You can change it to whatever you like. I have left it to what it is. Therefore I need to create that folder:</p>
<pre class="brush:bash">mkdir /var/cache/http-replicator</pre>
<p>Since I have specified that the user that this proxy will run as is portage (see &#8211;user directive above) I need to change the owner of my cache folder:</p>
<pre class="brush:bash">chown portage:portage /var/cache/http-replicator</pre>
<p>Prior to starting the service, there is a small change to be made to the init script. This is a bug which I do not know when it will be fixed but this workaround keeps everything running nice and smooth. I need to edit /etc/init.d/http-replicator and change:</p>
<pre>    ebegin "Starting Http-Replicator"
    start-stop-daemon --start --pidfile /var/run/http-replicator...</pre>
<p>to</p>
<pre>    ebegin "Starting Http-Replicator"
    start-stop-daemon --start --oknodo --pidfile /var/run/http-replicator...</pre>
<p>- The paramenter &#8211;oknodo has been added.</p>
<p>I saved the file and now I add the service to the default runlevel and start the service</p>
<pre class="brush:bash">rc-update add http-replicator default
/etc/init.d/http-replicator start</pre>
<p>NOTE: If you have a firewall using iptables, you will need to add the following rule:</p>
<pre class="brush:bash"># HTTP-REPLICATOR
-A INPUT --protocol tcp --source 10.13.18.0/24 --match state --state NEW --destination-port 8080 --jump ACCEPT</pre>
<p>You will need also to regularly run</p>
<pre class="brush:bash">repcacheman</pre>
<p>and</p>
<pre class="brush:bash">rm -rf /usr/portage/distfiles/*</pre>
<p>to clear the distfiles folder. I have added those in a bash script and I run it every night using my cron.</p>
<h4>Client setup</h4>
<p>In my clients I need to edit the /etc/make.conf and change the SYNC directive to:</p>
<pre class="brush:bash">http_proxy="http://ws1:8080"
RESUMECOMMAND=" /usr/bin/wget -t 5 --passive-ftp  \${URI} -O \${DISTDIR}/\${FILE}"</pre>
<p>I have commented any previous RESUMECOMMAND statements.</p>
<h4>Testing</h4>
<p>The testing begins in one of the clients (you can choose any package):</p>
<pre class="brush:bash">emerge logrotate</pre>
<p>and see in the output that everything works fine</p>
<pre>ws2 ~ # emerge logrotate
Calculating dependencies... done!

&gt;&gt;&gt; Verifying ebuild manifests

&gt;&gt;&gt; Emerging (1 of 1) app-admin/logrotate-3.7.8
&gt;&gt;&gt; Downloading 'http://distfiles.gentoo.org/distfiles/logrotate-3.7.8.tar.gz'
--2009-12-10 06:46:47--  http://distfiles.gentoo.org/distfiles/logrotate-3.7.8.tar.gz
Resolving ws1... 10.13.18.101
Connecting to ws1|10.13.18.101|:8080... connected.
Proxy request sent, awaiting response... 200 OK
Length: 43246 (42K)
Saving to: `/usr/portage/distfiles/logrotate-3.7.8.tar.gz'

100%[=============================&gt;] 43,246      --.-K/s   in 0s

2009-12-10 06:46:47 (89.6 MB/s) - `/usr/portage/distfiles/logrotate-3.7.8.tar.gz' saved [43246/43246]
.....</pre>
<h3>Final thoughts</h3>
<p>Setting up local proxies allows your network to be as efficient as possible. It does not only reduce the download time for your updates but it is also courteous to the Gentoo community. Since mirrors are run by volunteers or non-profit organizations, it is only fair to not abuse the resources by downloading an update more than once for your network.</p>
<p>I hope this quick guide will help you and your network <img src='http://www.niden.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-6325600846885391";
/* www.niden.net Blog 468x60 */
google_ad_slot = "1288968183";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h4  class="related_post_title">Related Posts</h4><ul class="related_post"><li>August 21, 2010 -- <a href="http://www.niden.net/2010/08/how-to-create-an-inexpensive-hourly-remote-backup/" title="Create an inexpensive hourly remote backup [How-To]">Create an inexpensive hourly remote backup [How-To]</a> (3)</li><li>November 16, 2009 -- <a href="http://www.niden.net/2009/11/gentoo-stage-1-installation/" title="Gentoo Stage 1 Installation [How-To]">Gentoo Stage 1 Installation [How-To]</a> (1)</li><li>January 10, 2010 -- <a href="http://www.niden.net/2010/01/how-to-create-a-ssl-certificate-linux/" title="Create a SSL Certificate (Linux) [How-To]">Create a SSL Certificate (Linux) [How-To]</a> (4)</li><li>November 24, 2009 -- <a href="http://www.niden.net/2009/11/chromium-os-part-3/" title="Chromium OS Part 3 [How-To]">Chromium OS Part 3 [How-To]</a> (1)</li><li>November 24, 2009 -- <a href="http://www.niden.net/2009/11/chromium-os-part-2/" title="Chromium OS Part 2 [How-To]">Chromium OS Part 2 [How-To]</a> (2)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.niden.net/2009/12/faster-rsync-and-emerge-in-gentoo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
