<?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>Karl Katzke &#187; howto</title>
	<atom:link href="http://www.karlkatzke.com/categories/howto/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.karlkatzke.com</link>
	<description>Geek of the Week</description>
	<lastBuildDate>Fri, 16 Dec 2011 19:54:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Backing Up Two Ways from Sunday</title>
		<link>http://www.karlkatzke.com/backing-up-two-ways-from-sunday/</link>
		<comments>http://www.karlkatzke.com/backing-up-two-ways-from-sunday/#comments</comments>
		<pubDate>Mon, 22 Feb 2010 18:25:07 +0000</pubDate>
		<dc:creator>karlkatzke</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[vmware]]></category>

		<guid isPermaLink="false">http://www.karlkatzke.com/?p=555</guid>
		<description><![CDATA[One method of backup or recovery isn&#8217;t enough. Period. No matter what anyone tells you, what the book says, what your boss says, or what you think you need, you need to be backing things up in many ways. Here&#8217;s a few examples. MySQL Theoretically, you could recover anything you needed from the binary log, [...]]]></description>
			<content:encoded><![CDATA[<p>One method of backup or recovery isn&#8217;t enough. Period. No matter what anyone tells you, what the book says, what your boss says, or what you think you need, you need to be backing things up in many ways. </p>
<p>Here&#8217;s a few examples. </p>
<h3>MySQL</h3>
<p>Theoretically, you could recover anything you needed from the binary log, as long as you&#8217;ve got a good starting point and a good ending point.  (This, by the way, is a good reason to flush the binary logs and take a backup on a regular basis.) What if your binary log&#8217;s corrupted, though? You need to fall back to a full SQL backup &#8230; which you&#8217;re doing regularly, right? </p>
<p>If your binary log is corrupted, any mirrors you are using that are based on that binary log are corrupted as well. </p>
<p>Case in point: I had a client with a very active, very large database&#8230; north of 15GB in InnoDB. The binary log hit a bug and corrupted itself. The backups were being done from that mirror so that they didn&#8217;t interrupt the main machine&#8217;s processing, but they only kept a few days worth, so we couldn&#8217;t use those backups to restore. The most recent un-corrupted dump from the main machine had been taken three months before. Luckily, the client had done some application-level backups to an XML format, and we were able to (laboriously) restore from that. It cost about $3,000 because they didn&#8217;t want to degrade their forum&#8217;s performance for a half hour every night and pay for an extra TB or storage or so to keep more than a few days worth of upgrades. </p>
<h3>Servers</h3>
<p>Scenario: Hard drive gets corrupted or dies. You need to get the machine back up quickly. You have a snapshot of the machine &#8230; but your snapshot is on the same storage as that machine unless you back it up somewhere else. </p>
<p>On top of that, storage requirements have been growing rapidly for servers. Where a linux server take less than 1GB, Windows 2008R2 can take up 20GB with system files alone. (In fact, if you plan to have any data on that server, or keep any logs, we&#8217;d recommend going with 40GB minimum for your C: drive.) It&#8217;s important to back that up to something that&#8217;s not on the same system disks. </p>
<p>Better yet, take a hint from the application-level backups &#8212; and back up your registry, configuration files, and data separately from the snapshot. We tend to use RSync for this role and put it in a rolling-backup mode with the &#8211;link-dest option to ease recovery. </p>
<h3>VMWare</h3>
<p>Same principle as above. Snapshots are usually stored in the same datastore. Datastore goes bye-bye, so do your snapshots. </p>
<p>There&#8217;s some great products out there that can really help with this issue. The one we use is <a href="http://www.veeam.com/vmware-esx-backup.html">VEEAM Replication and Backup</a>. It can be used to replicate a snapshot to another VMWare cluster, or back up the datastore files at a consistent snapshot point and then copy them elsewhere all in one step. We use a two-step process &#8212; we keep them locally on the backup server and also transmit them to another datacenter across campus. </p>
<p>When using VEEAM with Windows, make sure that VMWare Tools is installed and that you enable the VSS integration. (You&#8217;ll also need to make sure that the administrative share option on the system drives are enabled, and that the appropriate firewall ports are opened.) This ensures that you&#8217;ve got a transactionally consistent backup snapshot. </p>
<h3>Practice, practice, practice</h3>
<p>The only way to make sure that you can recover from a disaster is to test recovering from a disaster. At least once a year, we practice recovering from a worst-case scenario. That means bringing up a new machine from scratch, re-implementing all of the options and configurations, and then restoring the data. Despite that kind of restoration being something that should never happen, it does &#8212; and practice gives you insights into how to improve the processes and turns a recovery operation from an expensive nightmare that sets back all of your other processes into something that you can execute quickly and professionally. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkatzke.com/backing-up-two-ways-from-sunday/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IPMI / STONITH howto with Pacemaker</title>
		<link>http://www.karlkatzke.com/ipmi-stonith-howto-with-pacemaker/</link>
		<comments>http://www.karlkatzke.com/ipmi-stonith-howto-with-pacemaker/#comments</comments>
		<pubDate>Tue, 05 May 2009 14:11:43 +0000</pubDate>
		<dc:creator>karlkatzke</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://www.karlkatzke.com/?p=446</guid>
		<description><![CDATA[With Dell kit of 1950/860 and newer, I&#8217;m using the built in IPMI-over-LAN in the BIOS for stonith instead of messing with DRAC5 or more complicated means. It&#8217;s easy to configure on it&#8217;s own IP and it just plain works. First, a security note with people who have their machines on a &#8220;public&#8221; network: You&#8217;ll [...]]]></description>
			<content:encoded><![CDATA[<p>With Dell kit of 1950/860 and newer, I&#8217;m using the built in IPMI-over-LAN in the BIOS for stonith instead of messing with DRAC5 or more complicated means. It&#8217;s easy to configure on it&#8217;s own IP and it just plain works. </p>
<p>First, a security note with people who have their machines on a &#8220;public&#8221; network: You&#8217;ll want to disable or set a password for the &#8216;null&#8217; default user for ipmi. This may be done for you in recent versions of dell firmware, but it isn&#8217;t on some older stuff. Also, IPMI v. 1.5 doesn&#8217;t do encryption by default; you&#8217;ll want to make sure you set an encryption key in the bios settings and then use that when you connect (with the lanplus interface, and I have no idea what the syntax is with the stonith resource agent&#8230;) or you&#8217;ll be sending your authentication information &#8220;in the clear&#8221;. Since you need to have ADMINISTRATOR permission to reboot the machine as far as I know, you will want to make sure you have this secured&#8230; or anyone who&#8217;s sniffing can power your machines off at will. </p>
<p>You can test the sequence by using ipmitool. <code>ipmitool -H (ip address) -U (user) -a chassis power cycle</code> should cause your server to reboot after you enter the password. Please test this first. </p>
<p>Now all you need to do is add a configuration to your cluster. Using the pacemaker clm command line tool, just go <code>configure primitive (host)-stonith stonith:external/ipmi \<br />
params hostname=(host) ipaddr=(ip address) user=(user) passwd=(password) interface=lan</code>. Double check your stonith resource agents to be sure of the syntax. ( <code>crm# ra meta external/ipmi stonith</code> )</p>
<p>You&#8217;ll want to add constraints (out of the scope of this document, since it depends on your cluster design) so that a host won&#8217;t have it&#8217;s own stonith running on it. Although I&#8217;m thinking that a game of stonith-based russian roulette would be kinda fun as a computer art installation someday. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkatzke.com/ipmi-stonith-howto-with-pacemaker/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ocfs2 1.4 and Pacemaker</title>
		<link>http://www.karlkatzke.com/ocfs2-14-and-pacemaker/</link>
		<comments>http://www.karlkatzke.com/ocfs2-14-and-pacemaker/#comments</comments>
		<pubDate>Fri, 24 Apr 2009 18:22:29 +0000</pubDate>
		<dc:creator>karlkatzke</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[ocfs2 pacemaker o2cb]]></category>

		<guid isPermaLink="false">http://www.karlkatzke.com/?p=437</guid>
		<description><![CDATA[You can use pacemaker with ocfs 1.4, but when you&#8217;re running service o2cb configure, you need to specify the &#8220;cluster stack&#8221; pcmk instead of the default o2cb. I haven&#8217;t tested this myself yet, but if I don&#8217;t blog it, I know I&#8217;ll forget it.]]></description>
			<content:encoded><![CDATA[<p>You can use pacemaker with ocfs 1.4, but when you&#8217;re running <code>service o2cb configure</code>, you need to specify the &#8220;cluster stack&#8221; <code>pcmk</code> instead of the default <code>o2cb</code>. I haven&#8217;t tested this myself yet, but if I don&#8217;t blog it, I know I&#8217;ll forget it. <img src='http://www.karlkatzke.com/wp-includes/images/smilies/icon_razz.gif' alt=':-P' class='wp-smiley' />  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkatzke.com/ocfs2-14-and-pacemaker/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Subversion Power Tip: &#8211;parents</title>
		<link>http://www.karlkatzke.com/subversion-power-tip-parents/</link>
		<comments>http://www.karlkatzke.com/subversion-power-tip-parents/#comments</comments>
		<pubDate>Fri, 23 Jan 2009 21:38:42 +0000</pubDate>
		<dc:creator>karlkatzke</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[subversion]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://www.karlkatzke.com/?p=359</guid>
		<description><![CDATA[Let&#8217;s say you want to keep your logwatch configuration, which has a lot of files deep in directory trees, in subversion to track changes you make over time and ease rollouts between machines. When you want to check in /etc/logwatch/conf/logwatch.conf. Your working directory is /etc, but /logwatch and /logwatch.conf are not yet added. You don&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>Let&#8217;s say you want to keep your logwatch configuration, which has a lot of files deep in directory trees, in subversion to track changes you make over time and ease rollouts between machines. </p>
<p>When you want to check in <code>/etc/logwatch/conf/logwatch.conf</code>. Your working directory is /etc, but /logwatch and /logwatch.conf are not yet added. You don&#8217;t want to import everything under /etc/logwatch/scripts nor do you want to import anything under the /conf directory besides logwatch.conf. </p>
<p>svn clients >= version 1.5 have a really cool new feature. From an existing working directory, you can run <code>svn add logwatch/conf/logwatch.conf --parents</code> instead of first having to add logwatch with the -N option, conf with the -N option, and then finally logwatch.conf, &#8230; makes for a decent time savings. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkatzke.com/subversion-power-tip-parents/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux Docked Dell Precision M6300 Audio: No sound when Docked</title>
		<link>http://www.karlkatzke.com/linux-docked-dell-precision-m6300-audio-no-sound-when-docked/</link>
		<comments>http://www.karlkatzke.com/linux-docked-dell-precision-m6300-audio-no-sound-when-docked/#comments</comments>
		<pubDate>Tue, 05 Aug 2008 19:57:02 +0000</pubDate>
		<dc:creator>karlkatzke</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[opensuse]]></category>
		<category><![CDATA[audio]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[iec958]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://www.karlkatzke.com/?p=212</guid>
		<description><![CDATA[This has worked on OpenSuse 10.3, Fedora 9, and all recent versions of Ubuntu&#8230; Problem: Audio doesn&#8217;t work when the machine is docked in a Dell dock. Solution: You need to enable the IEC958 Switch in your Volume Control application. HowTo: Click Computer, More Applications, and Voume Control Click Edit, Preferences, and check IEC958. Then [...]]]></description>
			<content:encoded><![CDATA[<p>This has worked on OpenSuse 10.3, Fedora 9, and all recent versions of Ubuntu&#8230;</p>
<p>Problem: Audio doesn&#8217;t work when the machine is docked in a Dell dock.<br />
Solution: You need to enable the IEC958 Switch in your Volume Control application. </p>
<p>HowTo:</p>
<ol>
<li>Click Computer, More Applications, and Voume Control</li>
<li>Click Edit, Preferences, and check IEC958. Then click Close.</li>
<li>Switch from the Playback tab to the Switches tab, and check the IEC958 checkbox.</li>
</ol>
<p>I also clicked the IEC958 Default PCM box on my OpenSuSE 11 machine; this gave me control over the dock&#8217;s specific output port as opposed to the headphone port on the laptop. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkatzke.com/linux-docked-dell-precision-m6300-audio-no-sound-when-docked/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Subversion on OSX</title>
		<link>http://www.karlkatzke.com/subversion-on-osx/</link>
		<comments>http://www.karlkatzke.com/subversion-on-osx/#comments</comments>
		<pubDate>Thu, 12 Jun 2008 14:04:44 +0000</pubDate>
		<dc:creator>karlkatzke</dc:creator>
				<category><![CDATA[apple]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[macports]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[ports]]></category>
		<category><![CDATA[subversion]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://www.karlkatzke.com/?p=153</guid>
		<description><![CDATA[The version of the command-line svn client for OSX is badly out of date &#8212; I think it&#8217;s 1.1 or something stupid like that. (Apple has done a poor job of keeping command line utils up to date!) The SCPlugin available via the Tigris.org website is -OK-, but not great. There&#8217;s some things that it [...]]]></description>
			<content:encoded><![CDATA[<p>The version of the command-line svn client for OSX is badly out of date &#8212; I think it&#8217;s 1.1 or something stupid like that. (Apple has done a poor job of keeping command line utils up to date!) </p>
<p>The <a href="http://scplugin.tigris.org/">SCPlugin</a> available via the Tigris.org website is -OK-, but not great. There&#8217;s some things that it does that just don&#8217;t feel right&#8230; I&#8217;ve just never gotten used to using a GUI (even TortoiseSVN) to manage repositories. Plus, my Vim plugins don&#8217;t work with SCPlugin and I&#8217;d rather be able to control things without switching from terminal windows into gui windows. </p>
<p>Yes, I -am- old school &#8230;. but I know there&#8217;s others of me!</p>
<p>To install up-to-date versions of the svn command-line client, just follow these easy steps. </p>
<ol>
<li>Install X11 from your OSX DVD. It&#8217;s necessary to have X11 installed before you install xCode so that it pulls in the X11 sdk.</li>
<li>Download and install XCode 3.0 if you haven&#8217;t already.</li>
<li>Download and install <a href="http://www.macports.org/">MacPorts</a> and follow their directions until you can run #4&#8230;</li>
<li>&#8230; <code>sudo port -d selfupdate</code>. The -d flag tells it to output debug information, which gives you a better idea of what went wrong if it errored out. 
<p>Now, I ran into a small problem with the next step. You SHOULD just be able to <code>sudo port -d install subversion</code>&#8230; but it errored out because I didn&#8217;t have awk installed, or some other dependency was missing. At this point, I ran <code>sudo port install gawk</code> and then <code>sudo port deps subversion</code> &#8230; I installed the first few dependencies by hand, and after that it let me run <code>sudo port install subversion</code> and it safely installed the subversion client.</p>
<p>
</li>
</ol>
<p>And voila! You should be able to do things like you normally would with subversion from the command line in linux. Maybe it&#8217;s just how *I* learned, but I really do prefer working with subversion repositories via the command line. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkatzke.com/subversion-on-osx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Squirrelmail with Dovecot SMTP Auth</title>
		<link>http://www.karlkatzke.com/squirrelmail-with-dovecot-smtp-auth/</link>
		<comments>http://www.karlkatzke.com/squirrelmail-with-dovecot-smtp-auth/#comments</comments>
		<pubDate>Thu, 29 May 2008 15:39:19 +0000</pubDate>
		<dc:creator>karlkatzke</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[dovecot]]></category>
		<category><![CDATA[mail]]></category>
		<category><![CDATA[mail server]]></category>
		<category><![CDATA[smtp]]></category>
		<category><![CDATA[smtp auth]]></category>
		<category><![CDATA[squirrelmail]]></category>

		<guid isPermaLink="false">http://www.karlkatzke.com/?p=136</guid>
		<description><![CDATA[I forgot to mention something in yesterday&#8217;s post about configuring Postfix with Dovecot and turning on smtp authentication. When you&#8217;re configuring Squirrelmail, you need to make sure that it does smtp authentication. It doesn&#8217;t seem that the version that comes with any way to that that *I* could easily find. However, when you set up [...]]]></description>
			<content:encoded><![CDATA[<p>I forgot to mention something <a href="http://www.karlkatzke.com/centos-postfix-dovecot-spamassassin-postfixadmin-and-squirrelmail/">in yesterday&#8217;s post about configuring Postfix with Dovecot and turning on smtp authentication</a>.</p>
<p>When you&#8217;re configuring Squirrelmail, you need to make sure that it does smtp authentication. It doesn&#8217;t seem that the version that comes with any way to that that *I* could easily find. However, when you set up your config_local.php in squirrelmail (which with the RPM installs in /etc/squirrelmail/config_local.php), set up a user for smtp auth with it&#8217;s own password&#8230; example:</p>
<pre>$smtp_sitewide_user = 'smtpauth@katzke.net';
$smtp_sidewide_pass = 'somepassword';</pre>
<p>&#8230; and now Squirrelmail will be able to authenticate to send email!</p>
<p>Alternately, you could set email sent from localhost to always be allowed without having to authenticate, but this will still work if your mail server and webmail server are on different machines. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkatzke.com/squirrelmail-with-dovecot-smtp-auth/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>CentOS, Postfix, Dovecot, Spamassassin, Postfixadmin, and Squirrelmail</title>
		<link>http://www.karlkatzke.com/centos-postfix-dovecot-spamassassin-postfixadmin-and-squirrelmail/</link>
		<comments>http://www.karlkatzke.com/centos-postfix-dovecot-spamassassin-postfixadmin-and-squirrelmail/#comments</comments>
		<pubDate>Wed, 28 May 2008 02:47:07 +0000</pubDate>
		<dc:creator>karlkatzke</dc:creator>
				<category><![CDATA[centos]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[clamav]]></category>
		<category><![CDATA[dovecot]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[mail]]></category>
		<category><![CDATA[mailscanner]]></category>
		<category><![CDATA[postfix]]></category>
		<category><![CDATA[postfixadmin]]></category>
		<category><![CDATA[spamassassin]]></category>
		<category><![CDATA[squirrelmail]]></category>

		<guid isPermaLink="false">http://www.karlkatzke.com/?p=129</guid>
		<description><![CDATA[What a mouthful. Like most other americans who live on a budget, I&#8217;m taking a &#8220;staycation&#8221; this weekend. What better thing to do than to get my mail server migrated to my new VPS? Well, first, I suppose, I should get the mail server all working on the new VPS&#8230; In CentOS, the default Postfix [...]]]></description>
			<content:encoded><![CDATA[<p>What a mouthful. Like most other americans who live on a budget, I&#8217;m taking a &#8220;staycation&#8221; this weekend. What better thing to do than to get my mail server migrated to my new VPS? Well, first, I suppose, I should get the mail server all working on the new VPS&#8230; </p>
<p>In CentOS, the default Postfix package doesn&#8217;t have MySQL support built in. If you&#8217;ve got the priorities plugin installed, you&#8217;re either going to need to disable it or otherwise work around it so that you get the one from the centosplus repo. Other than that, it&#8217;s been made about as easy as it can be&#8230; just keep in mind as you&#8217;re reading this tutorial that I really loathe administering mail servers and consider it to be a quite onerous chore that&#8217;s been made even more onerous by spammers and hackers and script kiddies and what have you. </p>
<p>You&#8217;ll need to install:
<pre>yum install gcc postfix clamav mysql-server mysql-devel spamassassin
 dovecot php php-mbstring php-mysql rpm-build</pre>
<p>. There&#8217;s no RPM for Postfixadmin, but it&#8217;s available from <a href="http://sourceforge.net/projects/postfixadmin">the project&#8217;s site on Sourceforge.</a></p>
<p>And now the fun begins. This howto assumes that you have a decent level of knowledge and skill setting up services that run on Linux.<span id="more-129"></span>I&#8217;ve included my configuration files where appropriate, please note you&#8217;ll need to establish your own files associated with mysql, since the main purpose of those files is authentication. <b>Please read the documents on how to do this.</b> I&#8217;ve even linked to the correct pages.</p>
<p>Since Dovecot and Postfix hang off of postfixadmin, let&#8217;s get that installed first. Download the tarball, untar it somewhere (I use /opt/postfixadmin/), and point apache at it&#8230; basically, just add this into your virtual host container on the server: </p>
<pre>Alias /pfadmin/ "/opt/postfixadmin/"
<Directory "/opt/postfixadmin">
        Order allow,deny
        Allow from all
        DirectoryIndex index.php
</Directory></pre>
<p>Don&#8217;t forget to set up a database. I&#8217;m assuming you&#8217;re using mysql; as root:</p>
<pre>mysql> create database postfix;
Query OK, 1 row affected (0.01 sec)

mysql> grant all on postfix.* to postfix@localhost identified
 by 'passwordgoeshere';
Query OK, 0 rows affected (0.03 sec)</pre>
<p>Change the settings in /opt/postfixadmin/config.inc.php to reflect your server&#8217;s setup. If you are using MySQL >= 4.1, don&#8217;t forget to change the database type to mysqli&#8230; you&#8217;ll get much better performance. To finish setup, head to http://www.yourserver.com/pfadmin/setup.php and follow the prompts. You&#8217;ll want to have already pointed the domain&#8217;s MX at this IP address &#8212; that&#8217;s outside the scope of this tutorial, but rest assured that if you haven&#8217;t already done it, you&#8217;re going to want to go take a nice long nap &#8230; say, for a day or two &#8230; and come back when it resolves. Don&#8217;t add a domain or a mailbox yet.</p>
<h2>Postfix</h2>
<p>On to Postfix. Postfix is the mail transfer agent. In post office terms, Postfix is the guy at the central office who receives your mail from the truck or airplane, takes it out of the big bulk bag, filters it into your correct mailbox after applying any additional filters (i.e. &#8220;I&#8217;m on vacation, hold my mail&#8221;) to your individual account, and puts it in your P.O. box ready for you to pick up. </p>
<p>The official word on how to do postfix with mysql <a href="http://www.postfix.org/MYSQL_README.html">is available here</a>. Go read that, I&#8217;ll wait. </p>
<p>Before proceeding with the Postfix configuration, make sure that the postfix version you have has MySQL support built in. To do this, run <code>postconf -m</code> and verify that mysql appears in the list. If mysql isn&#8217;t there, uninstall postfix using yum, download the version from the centosplus repository, and install that one manually. </p>
<p>To get postfix working, you&#8217;ll need to tell it to use mysql virtual maps for it&#8217;s user and domain tables. I&#8217;ve posted my configuration files below to make it easy on you. There&#8217;s a decent walkthrough in the postfixadmin DOCUMENTS folder.   </p>
<ul>
<li>
<a href="http://www.karlkatzke.com/postfix-mastercf/">master.cf</a></li>
<p><a href="http://www.karlkatzke.com/postfix-maincf/">main.cf</a></li>
</ul>
<p>A few things of note:</p>
<ul>
<li>Note in postfix&#8217;s master.cf that I have ports 25 and 587 open. 587 is known as the alternate SMTP port, and us poor peons in the US with horrible ISPs that block port 25 for some misguided reason need to use it to pass mail to our servers.</li>
<li>The virtual_uid_maps and virtual_gid_maps need to be set to a user that postfix has access to (the postfix user is fine, but I created an extra user called vmail.) You will need to create /var/spool/mail/vmail and chown it over to the group ID and user ID that you&#8217;ve set in the configuration file.</li>
<li>Note the smtpd_auth_type and smtpd_auth_path settings &#8212; these are important to make sure that you are not hosting an open relay. Postfix can use dovecot instead of saslauthd &#8212; there&#8217;s no reason you should have to run two authentication mechanisms&#8230; is there? <a href="http://www.postfix.org/SASL_README.html#server_dovecot">Here&#8217;s documentation on sasl with dovecot.</a></li>
<li>Note that we also are using a static user ID of 502 for the vmail user that owns the virtual mailboxes &#8212; this MUST be set in both the postfix and dovecot mail configurations! Create a vmail user by calling `adduser -s /sbin/nologin vmail` as root, and then `addgroup vmail` &#8212; cat /etc/groups and /etc/passwd to get the user and group IDs, and set the group ID definitions in postfix (look for the lines that say static:###) and dovecot.</li>
</ul>
<h2>Dovecot</h2>
<p>The next step is to get Dovecot configured. Dovecot is the part that allows users to authenticate to the mail server and to get the mail from their mailbox. In post office terms, it&#8217;s the authentication mechanism (key or combination) that lets you into your private P.O. box. </p>
<p>Again, there&#8217;s a DOVECOT.txt in the postfixadmin/DOCUMENTS directory that will tell you what settings you need to change, but I&#8217;ve attached my file below. In round terms, what you need to do is set up the pop3 and IMAP servers for the appropriate locations, tell them to look in the mysql tables for the authentication information, etc. Please note that Dovecot changed it&#8217;s configuration file schema, so default_mail_env is now mail_location and a few other details. Depending on what version of dovecot you&#8217;re using (I&#8217;m using 1.0-1.2.rc15, which is the latest from centos) you might have to make some changes to the configuration files below. <a href="http://wiki.dovecot.org/AuthDatabase/SQL">There some very good information in the Dovecot wiki that you want to read before we go any farther.</a> </p>
<p><a href="http://www.karlkatzke.com/dovecotconf/">/etc/dovecot.conf</a></p>
<h2>Securing / Opening things up</h2>
<p>With both of those servers running, make sure you don&#8217;t have any errors in /var/log/maillog. Then make sure that your firewalls are open on ports 25, 110 and 143. (This tutorial doesn&#8217;t cover SSL/TLS. I&#8217;ll cover it at a later date &#8212; but I recommend that you go from here and follow the very easy instructions at both the postfix and dovecot websites to configure it yourself.)</p>
<p>With both dovecot and postfix running with users from the database, we should have a secure and working server. Let&#8217;s test it. Before we start testing, you&#8217;re going to need a hash of your username and password&#8230; this is the virtual mailbox you set up when you were setting up postfixadmin. The command to get this hash looks like:</p>
<p><font face="courier">perl -MMIME::Base64 -e &#8216;print encode_base64(&#8220;<font color="red">\000</font><font color="green">foo</font><font color="red">\@</font><font color="green">foobar.com</font><font color="red">\000</font><font color="green">foobar</font>&#8220;)&#8217;;</font></p>
<p>&#8230; replace the first green part with the email user&#8217;s name, then the second green part with the virutal domain we&#8217;re handling mail for, and the third green part with the user&#8217;s password. </p>
<p>Which would result in a hash of: </p>
<pre>AGZvb0Bmb29iYXIuY29tAGZvb2Jhcg==</pre>
<p>SMTP first. Open up a shell and telnet to your mailserver on port 25 or 587. You should be able to hold a session that looks something like this: </p>
<pre>
:~ karlkatzke$ telnet mailserver.com 587
Trying xx.xx.xx.xx...
Connected to mailserver.com.
Escape character is '^]'.
220 mailserver.com ESMTP Postfix
ehlo mail.foobar.net
250-mailserver.com
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-AUTH PLAIN
250-AUTH=PLAIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
auth plain foobar
535 5.7.0 Error: authentication failed:
auth plain AGZvb0Bmb29iYXIuY29tAGZvb2Jhcg==
235 2.0.0 Authentication successful
</pre>
<p>At this point you could send mail and see if it actually goes through. Google it if you need to figure it out, since I&#8217;m not going to really cover it much here. Let&#8217;s test Dovecot some though. Telnet to port 110 on your mailserver, and let&#8217;s use the same password hash to do something similar. (Note that you&#8217;ll have to have sent an email to the user first in order for the mailboxes to be created, so if you haven&#8217;t, do so!) </p>
<pre>
:~ karlkatzke$ telnet mailserver.com 110
Trying xx.xx.xx.xx...
Connected to mailserver.
Escape character is '^]'.
+OK Dovecot ready.
user foobar@mailserver.com
+OK
pass foobar
+OK Logged in.
list
+OK 2 messages:
1 601
2 486
.
quit
+OK Logging out.
Connection closed by foreign host.
</pre>
<p>Ok, you can receive mail, send mail, and everything else. If that&#8217;s all you want, you&#8217;re done. Just to make sure, head over to the <a href="http://www.abuse.net/relay.html">abuse.net relay test</a> and run a test against your server to make very sure you don&#8217;t have any open relays that could be used by spammers. Having open relays on your server WILL get you blacklisted almost immediately. </p>
<h2>Spam Assassin</h2>
<p>The easiest way to get spamassassin running is to follow <a href="http://onetforum.com/fourm/viewtopic.php?p=27">this tutorial</a>. Just remember that if you&#8217;re running SMTP on port 587, run spamassassin there too. Don&#8217;t forget to start and chkconfig the spamasssassin service before you restart postfix. </p>
<h2>Squirrelmail</h2>
<p>Install squirrelmail via yum. It&#8217;s easy &#8212; just install it, restart apache, and you&#8217;re good to go. <b>Update:</b> See <a href="http://www.karlkatzke.com/squirrelmail-with-dovecot-smtp-auth/">this blog article for SMTP auth</a>. </p>
<h2>Wrapping up</h2>
<p>This configuration, it should be noted, <b>is the one that works for me</b>. It may not work for you. It may not also follow the best security principles &#8212; I would especially recommend getting SSL/TLS working for any sort of deployment in the workplace. If you identify any security holes or problems, please post a comment below or email me via the contact page and I&#8217;ll update the tutorial. Also, please note the date the tutorial was published and check documentation files accordingly. Reading this tutorial and/or downloading the files is no replacement for actually reading the documentation.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkatzke.com/centos-postfix-dovecot-spamassassin-postfixadmin-and-squirrelmail/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Your First Zend Framework Application: Day Four</title>
		<link>http://www.karlkatzke.com/your-first-zend-framework-application-day-four/</link>
		<comments>http://www.karlkatzke.com/your-first-zend-framework-application-day-four/#comments</comments>
		<pubDate>Thu, 01 May 2008 14:07:06 +0000</pubDate>
		<dc:creator>karlkatzke</dc:creator>
				<category><![CDATA[first application]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[webdev]]></category>
		<category><![CDATA[zend framework]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zend]]></category>

		<guid isPermaLink="false">http://www.karlkatzke.com/?p=120</guid>
		<description><![CDATA[And now the fun begins! Today we&#8217;re going to really show some of the power of Zend Framework. All the steps that you&#8217;ve taken in the previous tutorials will suddenly make sense &#8212; you&#8217;re going to be set up to authenticate users in a few minutes flat. If you don&#8217;t know basic OOP (Object-Oriented Programming) [...]]]></description>
			<content:encoded><![CDATA[<p>And now the fun begins! Today we&#8217;re going to really show some of the power of Zend Framework. All the steps that you&#8217;ve taken in the previous tutorials will suddenly make sense &#8212; you&#8217;re going to be set up to authenticate users in a few minutes flat. </p>
<p>If you don&#8217;t know basic OOP (Object-Oriented Programming) principles, now would be a good time to go do some reading on them. We&#8217;re going to make heavy use of <a href="http://en.wikipedia.org/wiki/Inheritance_%28computer_science%29">inheritance</a>, as well as <a href="http://en.wikipedia.org/wiki/Method_overriding_%28programming%29">overriding</a>. Just keep in mind that PHP is not a strongly typed language. </p>
<p>Let&#8217;s get started. For authentication, we&#8217;re going to build the form the old fashioned way so that you can get a good example for &#8216;how it was done&#8217; versus &#8216;how smoothly it can be done&#8217; with Zend Framework. <span id="more-120"></span> Let&#8217;s create the login form. In /app/views/scripts/index/, create login.phtml &#8212; do note the .phtml extension on it. To keep us moving right along, here&#8217;s the code for it.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?</span> <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">message</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
    <span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">message</span><span style="color: #000000; font-weight: bold;">?&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;?</span> <span style="color: #b1b100;">endif</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
&lt;form name=&quot;login&quot; action=&quot;index/login&quot; method=&quot;post&quot;&gt;
Login: &lt;input type=&quot;text&quot; name=&quot;login&quot; /&gt;&lt;br /&gt;
Password: &lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;&lt;br /&gt;
&lt;input type=&quot;submit&quot; name=&quot;submit&quot; value=&quot;submit&quot; /&gt;
&lt;/form&gt;</pre></div></div>

<div id="rightbox" style="width:340;float:right;font-size: 10px;margin-left: 10px; padding: 3px  ; border: 1px dotted black; background-color: #fefefe"><b>All Zend Framework Tutorials</b><br /><a href="http://www.karlkatzke.com/your-first-zend-framework-application-day-four/" title="View post Your First Zend Framework Application: Day Four">Your First Zend Framework Application: Day Four</a><br />
<a href="http://www.karlkatzke.com/your-first-zend-framework-application-day-thre/" title="View post Your First Zend Framework Application: Day Three">Your First Zend Framework Application: Day Three</a><br />
<a href="http://www.karlkatzke.com/your-first-zend-framework-application-day-two/" title="View post Your First Zend Framework Application: Day Two">Your First Zend Framework Application: Day Two</a><br />
<a href="http://www.karlkatzke.com/your-first-zend-framework-application-day-one/" title="View post Your First Zend Framework Application: Day One">Your First Zend Framework Application: Day One</a>
</div>
<p>Now we&#8217;ll head back to your controller. If you look at the work you did in the form, you&#8217;ll see that the index controller&#8217;s login action will be responsible for both displaying and processing this form. </p>
<p>First, to get the form to display, you&#8217;ll need to add just a blank login action to your IndexController. For security purposes, I&#8217;ve cleared out the &#8216;list of users&#8217; that was in yesterday&#8217;s indexAction() (we don&#8217;t really want to give an attacker a list of users to try, do we?) and replaced it with a <a href="http://framework.zend.com/manual/en/zend.controller.dispatcher.html">call to $this->_forward()</a> to direct users that come to the index page to the login. Later on, when we&#8217;re checking for authenticated users, we&#8217;ll replace this with a conditional.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> IndexController <span style="color: #000000; font-weight: bold;">extends</span> Zend_Controller_Action <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">function</span> indexAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
     <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">forward</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'login'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  <span style="color: #000000; font-weight: bold;">function</span> loginAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Now, if you visit /index/login in your browser, you should get the login form. Let&#8217;s add some logic to make it do something. We&#8217;re going to use Zend_Auth&#8217;s database methods for this.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> loginAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$params</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_getAllParams<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$params</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'submit'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000088;">$params</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'submit'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'submit'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$auth</span> <span style="color: #339933;">=</span> Zend_Auth<span style="color: #339933;">::</span><span style="color: #004000;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000088;">$adapt</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Zend_Auth_Adapter_DbTable<span style="color: #009900;">&#40;</span>Zend_Registry<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'db'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$adapt</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setTableName</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'users'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$adapt</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setIdentityColumn</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$adapt</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setCredentialColumn</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$adapt</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setCredential</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">sha1</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$param</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$adapt</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setIdentity</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">htmlspecialchars</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$param</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'login'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$auth</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">authenticate</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$adapt</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">initView</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$result</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isValid</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	          <span style="color: #000088;">$storage</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Zend_Auth_Storage_Session<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                  <span style="color: #000088;">$storage</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">write</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$adapt</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getResultRowObject</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'id'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	          <span style="color: #000088;">$auth</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setStorage</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$storage</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 	          <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">view</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">message</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'Login Successful!'</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
	          <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">view</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">message</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'Invalid login. Please try again.'</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span> 
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>There&#8217;s a few very important things we want to note here. </p>
<ol>
<li>Zend_Auth is written in a <a href="http://en.wikipedia.org/wiki/Singleton_pattern">Singleton Pattern</a>.</li>
<li>We make use of the database handle that we stored in the registry in the front controller.</li>
<li>We&#8217;re encoding the password in the code before we send it to the database. In the database, the password is already encoded in sha1 format.</li>
<li>We&#8217;re setting the identity for later retrieval.</li>
<li>We pass a message back to the user via the view script.</li>
</ol>
<p>You know what? I know I promised that we&#8217;d get into some fancier stuff using Zend_Form and Zend_Mail, but I think that&#8217;s enough new concepts for one day. We&#8217;ll extend the tutorial into next week and spend tomorrow working with Zend_Form and Zend_Mail. </p>
<p>Happy coding!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkatzke.com/your-first-zend-framework-application-day-four/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Your First Zend Framework Application: Day Three</title>
		<link>http://www.karlkatzke.com/your-first-zend-framework-application-day-thre/</link>
		<comments>http://www.karlkatzke.com/your-first-zend-framework-application-day-thre/#comments</comments>
		<pubDate>Wed, 30 Apr 2008 19:54:28 +0000</pubDate>
		<dc:creator>karlkatzke</dc:creator>
				<category><![CDATA[first application]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[webdev]]></category>
		<category><![CDATA[zend framework]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zend]]></category>

		<guid isPermaLink="false">http://www.karlkatzke.com/?p=118</guid>
		<description><![CDATA[Today, let&#8217;s take a look at Zend_Db. Zend_Db implements a Table Data Gateway, in which the object is considered to be extended to have the properties of a table, as opposed to a Object Relational Model (ORM) / Data Access Object (DAO) where the object is considered to be a representation of the database object. [...]]]></description>
			<content:encoded><![CDATA[<p>Today, let&#8217;s take a look at Zend_Db. Zend_Db implements a Table Data Gateway, in which the object is considered to be extended to have the properties of a table, as opposed to a Object Relational Model (ORM) / Data Access Object (DAO) where the object is considered to be a representation of the database object. Philosophy aside, it&#8217;s a great tool, and we&#8217;re mostly interested in how to <i>use</i> it. It is worth noting that you can use <a href="http://www.karlkatzke.com/zend-framework-doctrine-2/">Zend Framework along with the excellent Doctrine ORM</a>&#8230; and the syntax is even pretty similar. </p>
<p>The general procedure when setting up Zend_Db is to create a bunch of objects that extend Zend_Db_Table_Abstract. When defining an object, you can define what table it connects to, what the primary key is, and any foreign keys that relate to it. Upon instantiating the object in your code, you can use it to build queries against it&#8217;s related table, which returns a collection of row sets for direct use in your applications. Today&#8217;s tutorial assumes that you&#8217;re very comfortable with looping and other control structures in PHP.<span id="more-118"></span></p>
<h2>Configuration File</h2>
<div id="rightbox" style="width:340;float:right;font-size: 10px;margin-left: 10px; padding: 3px  ; border: 1px dotted black; background-color: #fefefe"><b>All Zend Framework Tutorials</b><br /><a href="http://www.karlkatzke.com/your-first-zend-framework-application-day-four/" title="View post Your First Zend Framework Application: Day Four">Your First Zend Framework Application: Day Four</a><br />
<a href="http://www.karlkatzke.com/your-first-zend-framework-application-day-thre/" title="View post Your First Zend Framework Application: Day Three">Your First Zend Framework Application: Day Three</a><br />
<a href="http://www.karlkatzke.com/your-first-zend-framework-application-day-two/" title="View post Your First Zend Framework Application: Day Two">Your First Zend Framework Application: Day Two</a><br />
<a href="http://www.karlkatzke.com/your-first-zend-framework-application-day-one/" title="View post Your First Zend Framework Application: Day One">Your First Zend Framework Application: Day One</a>
</div>
<p>You should have a MySQL database accessible to your webserver. Knowing how to use MySQL is outside of the scope of this tutorial but the basic gist of what you need to do is &#8212; create a database, create a user and password for that database, and insert the SQL to create the tables. </p>
<p><a href='http://www.karlkatzke.com/wp-content/uploads/2008/04/zfapp.sql' target="_blank">ZFApp (Day 3) SQL</a></p>
<p>When you&#8217;ve collected that information, let&#8217;s write a configuration file. This file will go in app/config/db.ini.</p>

<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;"><span style="color: #000066; font-weight:bold;"><span style="">&#91;</span>dev<span style="">&#93;</span></span>
database.params.host<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">localhost</span>
database.adapter<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">pdo_mysql</span>
database.params.username<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">foobaruser</span>
database.params.password<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">foobar</span>
database.params.dbname<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">zfapp</span></pre></div></div>

<p>Save that file, and then let&#8217;s go tell the front controller how to access the zfapp database. </p>
<h2>Front Controller</h2>
<p>The first thing we need to do is go back and visit our friend the Front Controller. It needs some setup if we&#8217;re to use Zend_Db. Let&#8217;s open up index.php and add a few lines. We&#8217;ll be using Zend_Config_Ini to load up the configuration file. Note the &#8216;dev&#8217; &#8211; that tells us to load up the area after the [dev] in the above .ini file. I use this to tell the difference between my dev and live configuration, since that keyword is set by a SetEnv statement in the Apache configuration file.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$dbconf</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Zend_Config_Ini<span style="color: #009900;">&#40;</span>BASEDIR<span style="color: #339933;">.</span><span style="color: #0000ff;">'/app/config/db.ini'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'dev'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Now that we&#8217;ve got a handle to the configuration file, we&#8217;ll use Zend_Db&#8217;s factory method to create a DB Connection.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> Zend_Db<span style="color: #339933;">::</span><span style="color: #004000;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$dbconf</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">database</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>That&#8217;s it. That&#8217;s all we need to do. $db is now a database handle. Two lines of code! Zing! The only other things that we&#8217;ll find helpful here is setting this DB handle as the default handle for tables. I also register the DB handle with the registry so that I have an easy way to get it back later if I want to do something deep and complicated with the db.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">Zend_Db_Table_Abstract<span style="color: #339933;">::</span><span style="color: #004000;">setDefaultAdapter</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$db</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
Zend_Registry<span style="color: #339933;">::</span><span style="color: #004000;">set</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'db'</span><span style="color: #339933;">,</span><span style="color: #000088;">$db</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h2>Using the DB</h2>
<p>Tomorrow, we&#8217;ll really get into using the database for something, but for today let&#8217;s just finish the prep work and make a basic use of our new toy. </p>
<p>First, we need a model to access. Make sure you&#8217;ve got the models on your include path in your front controller:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #990000;">set_include_path</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">ini_get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'include_path'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span>PATH_SEPARATOR<span style="color: #339933;">.</span>BASEDIR<span style="color: #339933;">.</span><span style="color: #0000ff;">'app/models'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Now, we&#8217;ll create our first model. A model is a basic file that just tells the database driver where a table is, and provides some defaults. In /app/models/users.php, we&#8217;ll want to extend a Zend_Db_Table_Abstract as follows:</p>
<pre>
class Users extends Zend_Db_Table_Abstract {
   protected $_name = 'users';
   protected $_primary = 'id
}
</pre>
<p>&#8230; and that&#8217;s it. Since you included the models directory in your include path, all you need to do is instantiate a Users module anywhere in your application, and you can access the users table via the db handle you created in your front controller and assigned as default. Pretty neat, huh?</p>
<p>Ok, let&#8217;s select some rows out. </p>
<p>Head over to the /app/controllers/IndexController.php that you made yesterday. In the indexAction() function, place this code:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> indexAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">initView</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Initialize the view object for this module</span>
  <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Users<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Users Table Object. </span>
  <span style="color: #000088;">$rowset</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Created a default 'select all' query</span>
  <span style="color: #000088;">$list_of_users</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rowset</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$row</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$list_of_users</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$row</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">id</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">view</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">userlist</span> <span style="color: #339933;">=</span> <span style="color: #990000;">join</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$list_of_users</span><span style="color: #339933;">,</span><span style="color: #0000ff;">', '</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Concatenate the list of users and make it available to the view. </span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>And we&#8217;ll head over to the view script you created yesterday &#8230; /app/views/scripts/index/index.phtml &#8230; and add in a line to echo that userlist. Don&#8217;t forget to add the carat-questionmarks here, of course.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">userlist</span><span style="color: #339933;">;</span></pre></div></div>

<p>&#8230; and as Emeril says, Bang! You&#8217;re reading from your database. </p>
<p>Tomorrow we&#8217;ll do some &#8216;heavy&#8217; lifting &#8212; we&#8217;ll set up Zend_Auth to authenticate users from the database, a Zend_Form to allow users to sign up, and a Zend_Mail to send users their passwords when they&#8217;ve forgotten it. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkatzke.com/your-first-zend-framework-application-day-thre/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>

