<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
        <title>Ramblings of a web guy</title>
        <description>Brian Moon, of dealnews.com, shares what he knows (and learns) about PHP, MySQL and other stuff</description>
        <link>http://brian.moonspot.net/feed.php?type=rss&amp;amp;tag=</link>
        <lastBuildDate>Thu, 11 Mar 2010 08:13:21 -0600</lastBuildDate>
        <generator>Wordcraft 0.10</generator>
        <item>
            <guid>http://brian.moonspot.net/php-progress-bar</guid>
            <title>PHP command line progress bar</title>
            <link>http://brian.moonspot.net/php-progress-bar</link>
            <description><![CDATA[Was just looking through some code and came across this function I wrote some time ago. If you do a lot of your processing scripts in PHP like we do, you probably need to know what is going on sometimes. So, I made a progress bar for use on the cli. I thought I would share it.&nbsp; <a href="http://www.screencast.com/users/brianlmoon/folders/Jing/media/822d9970-a6a3-4071-bdc6-1303cce9800a">Here is a video</a> of it in action. And the <a href="http://brian.moonspot.net/status_bar.php.txt">code can be found here</a>.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Wed, 10 Mar 2010 11:33:34 -0600</pubDate>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/develop-for-production</guid>
            <title>Developers should write code for production</title>
            <link>http://brian.moonspot.net/develop-for-production</link>
            <description><![CDATA[Having development and staging environments that reflect production is a
 key component of DevOps.&nbsp; An example for us is dealing with our CDN. <br><br>I can imagine in some dysfunctional, fragmented company, a developer works on a web application and sticks all the images in the local directory with his scripts. Then some operations/deployment guy has to first move the images where they need to be and then change all the code that references those images.&nbsp; If he is lucky, he has a script that does it for him. This is a needless exercise. If you have a development environment that looks and acts like production, this is all handled for you.<br><br>Here is an example of how it works for us. We use a CDN for all images, javascript, CSS and more. Those files come from a set of domains: s1.dlnws.com - s5.dlnws.com. So, our dev environments have similar domains. somedev.s5.dlnws.com points to a virtual server. We then use mod_substitute in Apache to rewrite those URLs on the dev machine. Each developer and staging instances will have an Apache configuration such as:

<pre>Substitute "s|http://s1.dlnws.com|http://somedev.s1.dev.dlnws.com|in"<br>Substitute "s|http://s2.dlnws.com|http://somedev.s2.dev.dlnws.com|in"<br>Substitute "s|http://s3.dlnws.com|http://somedev.s3.dev.dlnws.com|in"<br>Substitute "s|http://s4.dlnws.com|http://somedev.s4.dev.dlnws.com|in"<br>Substitute "s|http://s5.dlnws.com|http://somedev.s5.dev.dlnws.com|in"<br></pre>

So our developers put the production URLs for images into our code. When they test on the development environment, they get URLs that point to their instance, not production. No fussing with images after the fact.<br><br>In addition to this, we use mod_proxy to emulate our production load balancers. Special request routing happens in production. We need to see that when developing so we don't deploy code that does not work in that circumstance. If the load balancers send all requests coming in to /somedir to a different set of servers, we have mod_proxy do the same thing to a different VirutalHost in our Apache configuration. It is not always perfect, but it gets us as close to production as we can get without buying very expensive load balancers for our development environments.<br><br>Of course, we did not come to this overnight. It took us years to get to this point. Maybe it won't take you that long. Keep in mind when creating your development environments to make them work like production. It is neat to be able to write code on your laptop. I did it for years. But, at some point before you send out code for production, the <strong>developer</strong> should run it on a production like environment. Then deploying should be much easier.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Wed, 03 Mar 2010 11:20:02 -0600</pubDate>
            <category>devops</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/devops-just-makes-sense</guid>
            <title>DevOps is the only way it has ever made sense</title>
            <link>http://brian.moonspot.net/devops-just-makes-sense</link>
            <description><![CDATA[<a href="http://www.kartar.net/2010/02/what-devops-means-to-me/">DevOps</a> is the label being given to the way we have always done things. This is not the first time this has happened. As it says on my <a href="/about/">About Me</a> page,<br><br><blockquote><em>Brian Moon has been working with the LAMP platform since before it was 
called LAMP.</em><br><br></blockquote>At some point, not sure when, someone came up with <a href="http://en.wikipedia.org/wiki/LAMP_%28software_bundle%29">LAMP</a>. I started working on what is now considered LAMP in 1996. I have seen lots of acronyms come and some go. We started using "Remote Scripting" after hearing <a href="http://terrychay.com/article/liquid-remote-scripting.shtml">Terry Chay</a> talk about it at OSCON. The next OSCON, AJAX was all the rage. Technically, we never used AJAX. The X stands for XML. We didn't use XML. What made sense for us was to send back javascript arrays and objects that the javascript interpreter could deal with easily. We wrote a PHP function called to_javascript that converted a PHP array into a javascript array. Sound familiar? Yeah, two years later, JSON was all the rage.<br><br>We also have seen the same thing with how we run our development process.&nbsp; We always considered our team to be an agile development team. That is agile with <a href="http://apsblog.burtongroup.com/2008/09/---font-definit.html">little a</a>. Nowadays, "Agile" with the big A is usually all about how you develop software and not about actually delivering the software. So, I am always perplexed when people ask me if we use "Agile" development. Are they talking little a or big A?<br><br>Today I came across the term DevOps on twitter (there is no Wikipedia page yet). We have always had an integrated development and operations team. I could be writing code in the morning and configuring servers in the afternoon. Developers all have some level of responsibility over managing their development environment. They updated their Apache configurations from SVN and make changes as needed for their applications. The development environments are simulated as close as possible to production. Developers roll code to the production servers. It is their responsibility to make sure it works on production. They also roll it when it is ready rather than letting it sit around for days. This means if there is an unforeseen issue, the code is fresh on their minds and the problem can quickly be solved. We have done things this way since 1998. We are not the only ones. The great guys at Flickr gave a great talk last year at Velocity about their <a href="http://velocityconference.blip.tv/file/2284377/">DevOps environment</a>. People were amazed at how their teams worked together.<br><br>One of the huge benefits of being a DevOps team is that we can utilize the full stack in our application. If we can use the load balancers, Apache or our proxy servers to do something that offloads our application servers, we plan for that in the development cycle. It is a forethought instead of an afterthought. I see lots of PHP developers that do everything in code. Their web servers and hardware are just there to run their code. Don't waste those resources. They can do lots of things for you.<br><br>One cool thing about this is that I now have a label to use when people ask us about our team. I can now say we are an agile DevOps team. They can then go look that up and see what it means. Maybe it will lead to less explanation of how we work too. And if we are lucky, maybe we can find people to hire that have been in a similar environment.<br><br>So, I welcome all the new people into the "DevOps movement". Adopt the 
ideas and avoid any rules that books, blogs, "experts" may want to come up with. The first time I see someone list themselves as a DevOps management specialist, I will die a little on the inside. It is not a set of rules, it is a way of thinking, even a way of life. If the process prevents you from doing something, you are 
using it wrong, IMO.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 22 Feb 2010 20:24:32 -0600</pubDate>
            <category>devops</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/browser-stats-januaray-2010</guid>
            <title>State of the Browsers and ad blocking</title>
            <link>http://brian.moonspot.net/browser-stats-januaray-2010</link>
            <description><![CDATA[In my last post about CSS layout and ads, a commenter brought up that the <a href="http://dealnews.com/">dealnews.com</a> web site did not handle extensions like Ad Block very gracefully. To which I responded that I don't care. To which he responded with download counts. Well, the reason I don't care is that ad impressions when compared to page views on dealnews.com are within 2% of each other. So, at best, less than 2% of users are blocking ads. In reality, that is going to include some DNS failures, network issues, or something else. I would bet our logo graphic has about the same difference. The reality is that <strong>normal people</strong> don't block ads. In <em>my opinion</em>, if you make your money by working on the web, you shouldn't either. I should add that this site's (my geeky blog) ad views was about 16% lower than the recorded page views. So, geeks block ads more I guess. But, geeks have dominated the web for a long time.<br><br>This got me thinking that I had not look at the browser stats very much lately. dealnews has a very odd graph on browser statistics. We do not follow the industry averages. Our audience is dominantly tech savy (that does not mean geeks). Our users don't just use the stuff that is installed on the computer when they get it. This kind of proves my point about ad blocking even more. We have non-moron users and they still don't block ads.<br><br>
<div style="text-align: center;"><img  alt="" style="width: 479px;" src="http://content.screencast.com/users/brianlmoon/folders/Jing/media/ec59e0db-b1f2-434b-afbb-13baf06d6ccb/00000065.png" align="middle"><br></div><br>
<table align="center" border="0" cellpadding="0" cellspacing="0">
 <tbody><tr align="left">
 <th>Browser</th>
 <th>&nbsp;&nbsp;% of Visits</th>
 </tr>
 <tr align="left">
 <td align="right">Internet Explorer</td>
 <td align="right">42.34%</td>
 </tr>
 <tr><td>Firefox</td>
 <td align="right">36.94%</td>
 </tr>
 <tr><td>Safari</td>
 <td align="right">9.55%</td>
 </tr>
 <tr><td>Chrome</td>
 <td align="right">8.34%</td>
 </tr>
 <tr><td>Mozilla</td>
 <td align="right">1.46%</td>
 </tr>
 <tr><td>Opera</td>
 <td align="right">0.68%</td>
 </tr>
 <tr><td>Netscape</td>
 <td align="right">0.41%</td>
 </tr>
 <tr><td>Avant</td>
 <td align="right">0.08%</td>
 </tr>
 <tr><td>Camino</td>
 <td align="right">0.06%</td>
 </tr>
 <tr><td style="text-align: left;">IE Mobile</td>
 <td align="right">0.02%</td>
 </tr>
</tbody></table>

<br>
As you can see, Firefox is very prevalent on our site. We generally test in IE7/8, Firefox 3, Safari and Chrome. I will occasionally test a major change in Opera. Typically, well formed HTML and CSS works fine in Opera so everything is all good.<br><br>As for operating systems, Windows still dominates, but we have more Macs than the average site I would guess.<br><br><div style="text-align: center;"><img  alt="" src="http://content.screencast.com/users/brianlmoon/folders/Jing/media/845bd3a9-dfbe-4487-9c17-1346e8d3db23/00000066.png" align="middle"><br></div><br>
<table align="center" border="0" cellpadding="0" cellspacing="0">
 <tbody><tr>
 <th align="left">OS</th>
 <th align="right">&nbsp;&nbsp;% of Visits</th>
 </tr>
 <tr>
 <td>Windows</td>
 <td align="right">82.95%</td>
 </tr>
 <tr><td>Macintosh</td>
 <td align="right">11.27%</td>
 </tr>
 <tr><td>iPhone</td>
 <td align="right">3.80%</td>
 </tr>
 <tr><td>Linux</td>
 <td align="right">1.19%</td>
 </tr>
 <tr><td>Android</td>
 <td align="right">0.17%</td>
 </tr>
</tbody></table>
<br>
Interesting that iPhone beats out Linux. That is just another sign to me that Linux is still not a real choice for real people. Be that a product issue from OEMs or user choice. That is debatable. It is notable that most of our company uses Macs. I don't think we make up a speck of that traffic though. If we did, our home state of Alabama would be our most dominant. It isn't. We are very typical in that regard, California is number one. We only have one employee there.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 01 Feb 2010 23:25:55 -0600</pubDate>
            <category>design</category>
            <category>firefox</category>
            <category>iphone</category>
            <category>web</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/using-tables-for-layout</guid>
            <title>Tables for layout</title>
            <link>http://brian.moonspot.net/using-tables-for-layout</link>
            <description><![CDATA[I just read <em><a href="http://www.rooftopsolutions.nl/article/264">A case for table-based
design</a></em> and was thrilled to know I am not the only one that
drowns in div soup from time to time.&nbsp; I do not for the most
part use tables for layout, but there are some cases where I just
can't make a set of divs do my bidding. The classic example is
having a two column layout where the left column <strong>LOADS
FIRST</strong> and is elastic and the right column is a fixed
size.&nbsp; The "loads first" is important in a world where the
rendering time of pages has become important.&nbsp; Ideally with
any page, the most important content would render first for the
user. In my case, this fixed column is an ad. As a web developer, I
don't care when the ad loads. The ads are a necessary evil in my
page layout. I must ensure that they load in an acceptable time
frame, but certainly not the first thing on the page. The specific
layout I am talking about is that of the top of dealnews.com.&nbsp;
It has a fixed size 300x250 ad on the right of the page and the
left side is elastic. I fiddled with divs for hours to get that to
act the way I wanted it to act. We use the grid CSS from <a href="http://oocss.org/grids_docs.html">OOCSS.org</a>. Wonderful piece
of CSS that is. But, even with that in hand, I could not get the
elements to behave, in all browsers, the way I could with a simple
two column table where the left column's width is set to 100% and
the right column contains a div of width 300 pixels. It was so easy
to pull that off. Maybe CSS3 is going to solve this problem? I
don't know. If you have the magic CSS that can do what this page
does, let me know.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Fri, 29 Jan 2010 10:01:39 -0600</pubDate>
            <category>html</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/php-ob-start-headers</guid>
            <title>ob_start and HTTP headers</title>
            <link>http://brian.moonspot.net/php-ob-start-headers</link>
            <description><![CDATA[I was helping someone in IRC deal with some "headers already sent" issues and told them to use <a href="http://php.net/manual/en/function.ob-start.php">ob_start</a>. Very diligently, the person went looking for why that was the right answer. He did not find a good explination. I looked around and I did not either. So, here is why this happens and why ob_start can fix it.<br><br><strong>How HTTP works</strong><br><br>HTTP is the communication protocol that happens between your web server and the user's browser.&nbsp; Without too much detail, this is broken into two pieces of data: headers and the body.&nbsp; The body is the HTML you send. But, before the body is sent, the HTTP headers are sent. Here is an example of an HTTP request response including headers:<br><code>HTTP/1.1 200 OK<br>Date: Fri, 29 Jan 2010 15:30:34 GMT<br>Server: Apache<br>X-Powered-By: PHP/5.2.12-pl0-gentoo<br>Set-Cookie: WCSESSID=xxxxxxxxxxxxxxxxxxxxxxxxxxxx; expires=Sun, 28-Feb-2010 15:30:34 GMT; path=/<br>Content-Encoding: gzip<br>Vary: Accept-Encoding<br>Keep-Alive: timeout=15, max=99<br>Connection: Keep-Alive<br>Transfer-Encoding: chunked<br>Content-Type: text/html; charset=UTF-8<br><br>
&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;<br>&lt;html&gt;<br> &lt;head&gt;<br> &lt;title&gt;Ramblings of a web guy&lt;/title&gt;<br>.<br>.<br>
</code>
So, all those lines before the HTML starts have to come first. HTTP headers are where things like cookies and redirection occur. When a PHP script starts to send HTML out to the browser, the headers are stopped and the body begins. When your code tries to set a cookie after this has started, you get the "headers already sent" error message.<br><br><strong>How ob_start works</strong><br><br>So, how does ob_start help? The ob in ob_start stands for output buffering. ob_start will buffer the output (HTML) until the page is completely done. Once the page is completely done, the headers are sent and then the output is sent. This means any calls to setcookie or the header function will not cause an error and will be sent to the browser properly. You do need to call ob_start before any output occurs. If you start output, it is too late.<br><br><strong>The down side</strong><br><br>The down side of doing this is that the output is buffered and sent all at once. That means that the time between the user request and the time the first byte gets back to the user is longer than it has to be. However, in modern PHP application design, this is often already the case. An MVC framework for example would do all the data gathering before any presentation is done. So, your application may not have any issue with this.<br><br>Another down side is that you (or someone) could get lazy and start throwing setcookie calls in any old place. This should be avoided. It is simply not good programming design. In a perfect world, we would not need output buffering to solve this problem for us.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Fri, 29 Jan 2010 10:00:00 -0600</pubDate>
            <category>http</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/using-ini-files-for-php-application-settings</guid>
            <title>Using ini files for PHP application settings</title>
            <link>http://brian.moonspot.net/using-ini-files-for-php-application-settings</link>
            <description><![CDATA[At dealnews we have three tiers of servers. First is our development servers, then staging and finally production. The complexity of the environment increases at each level. On a development server, everything runs on the localhost: mysql, memcached, etc. At the staging level, there is a dedicated MySQL server. In production, it gets quite wild with redundant services and two data centers.<br><br>One of the challenges of this is where and how to store the connection information for all these services. We have done several things in the past. The most common thing is to store this information in a PHP file. It may be per server or there could be one big file like:<br><br>

<code>

&lt;?php<br>

<br>

if(DEV){<br>

&nbsp;&nbsp;&nbsp;&nbsp;$server = "localhost";<br>

} else {<br>

&nbsp;&nbsp;&nbsp;&nbsp;$server = "10.1.1.25";<br>

}<br>

<br>

?&gt;

</code><br><br>This gets messy quickly. Option two is to deploy a single file that has the settings in a PHP array. And that is a good option. But, we have taken that one step further using some PHP ini trickeration. We use ini files that are loaded at PHP's startup and therefore the information is kept in PHP's memory at all times.<br><br>When compiling PHP, you can specify the --with-config-file-scan-dir to tell PHP to look in that directory for additional ini files. Any it finds will be parsed when PHP starts up. Some distros (Gentoo I know) use this for enabling/disabling PHP extensions via configuration. For our uses we put our custom configuration files in this directory. FWIW, you could just put the above settings into php.ini, but that is quite messy, IMO.<br><br>To get to this information, you can't use ini_get() as you might think.&nbsp; No, you have to use get_cfg_var() instead. get_cfg_var returns you the setting, in php.ini or any other .ini file when PHP was started. ini_get will only return values that are registered by an extension or the PHP core. Likewise, you can't use ini_set on these variables. Also, get_cfg_var will always reflect the initial value from the ini file and not anything changed with ini_set.<br><br>So, lets look at an example.<br><br>

<code>

;&nbsp;db.ini<br>

[myconfig]<br>

myconfig.db.mydb.db&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;mydb<br>

myconfig.db.mydb.user&nbsp;&nbsp;&nbsp;=&nbsp;user<br>

myconfig.db.mydb.pass&nbsp;&nbsp;&nbsp;=&nbsp;pass<br>

myconfig.db.mydb.server&nbsp;=&nbsp;host</code><br>



<br>This is our ini file. the group in the braces is just for looks. It has no impact on our usage. Because this is parsed along with the rest of our php.ini, it needs a unique namespace within the ini scope. That is what myconfig is for. We could have used a DSN style here, but it would have required more parsing in our PHP code.<br><br>



<code>



&lt;?php<br>

<br>

/**<br>

&nbsp;*&nbsp;Creates&nbsp;a&nbsp;MySQLi&nbsp;instance&nbsp;using&nbsp;the&nbsp;settings&nbsp;from&nbsp;ini&nbsp;files<br>

&nbsp;*<br>

&nbsp;*&nbsp;@author&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Brian&nbsp;Moon&nbsp;&lt;brianm@dealnews.com&gt;<br>

&nbsp;*&nbsp;@copyright&nbsp;&nbsp;1997-Present&nbsp;dealnews.com,&nbsp;Inc.<br>

&nbsp;*<br>

&nbsp;*/<br>

<br>

class&nbsp;MyDB&nbsp;{<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;/**<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Namespace&nbsp;for&nbsp;my&nbsp;settings&nbsp;in&nbsp;the&nbsp;ini&nbsp;file<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br>

&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;INI_NAMESPACE&nbsp;=&nbsp;"dealnews";<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;/**<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Creates&nbsp;a&nbsp;MySQLi&nbsp;instance&nbsp;using&nbsp;the&nbsp;settings&nbsp;from&nbsp;ini&nbsp;files<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;&nbsp;string&nbsp;&nbsp;$group&nbsp;&nbsp;The&nbsp;group&nbsp;of&nbsp;settings&nbsp;to&nbsp;load.<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;&nbsp;object<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br>

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;init($group)&nbsp;{<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;$dbs&nbsp;=&nbsp;array();<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!is_string($group))&nbsp;{<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Exception("Invalid&nbsp;group&nbsp;requested");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(empty($dbs["group"])){<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$prefix&nbsp;=&nbsp;MyDB::INI_NAMESPACE.".db.$group";<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$db&nbsp;&nbsp;&nbsp;=&nbsp;get_cfg_var("$prefix.db");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$host&nbsp;=&nbsp;get_cfg_var("$prefix.server");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$user&nbsp;=&nbsp;get_cfg_var("$prefix.user");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$pass&nbsp;=&nbsp;get_cfg_var("$prefix.pass");<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$port&nbsp;=&nbsp;get_cfg_var("$prefix.port");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(empty($port)){<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$port&nbsp;=&nbsp;null;<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sock&nbsp;=&nbsp;get_cfg_var("$prefix.socket");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(empty($sock)){<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sock&nbsp;=&nbsp;null;<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dbs[$group]&nbsp;=&nbsp;new&nbsp;MySQLi($host,&nbsp;$user,&nbsp;$pass,&nbsp;$db,&nbsp;$port,&nbsp;$sock);<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!$dbs[$group]&nbsp;||&nbsp;$dbs[$group]-&gt;connect_errno){<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Exception("Invalid&nbsp;MySQL&nbsp;parameters&nbsp;for&nbsp;$group");<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$dbs[$group];<br>

<br>

&nbsp;&nbsp;&nbsp;&nbsp;}<br>

<br>

}<br>

<br>

?&gt;



</code>

<br><br>We can now call DB::init("myconfig") and get a mysqli object that is connected to the database we want. No file IO was needed to load these settings except when the PHP process started initially.&nbsp; They are truly constant and will not change while this process is running.<br><br>Once this was working, we created separate ini files for our different datacenters. That is now simply configuration information just like routing or networking configuration. No more worrying in code about where we are.<br><br>We extended this to all our services like memcached, gearman or whatever. We keep all our configuration in one file rather than having lots of them. It just makes administration easier. For us it is not an issue as each location has a unique setting, but every server in that location will have the same configuration.<br><br>Here is a more real example of how we set up our files.<br><br>



<code>

[myconfig.db]<br>

myconfig.db.db1.db&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db1<br>

myconfig.db.db1.server&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db1hostname<br>

myconfig.db.db1.user&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db1username<br>

myconfig.db.db1.pass&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db1password<br>

<br>

myconfig.db.db2.db&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db2<br>

myconfig.db.db2.server&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db2hostname<br>

myconfig.db.db2.user&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db2username<br>

myconfig.db.db2.pass&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;db2password<br>

<br>

[myconfig.memcache]<br>

myconfig.memcache.app.servers&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;10.1.20.1,10.1.20.2,10.1.20.3<br>

myconfig.memcache.proxy.servers&nbsp;&nbsp;=&nbsp;10.1.20.4,10.1.20.5,10.1.20.6<br>

<br>

[myconfig.gearman]<br>

myconfig.gearman.workload1.servers&nbsp;=&nbsp;10.1.20.20<br>

myconfig.gearman.workload2.servers&nbsp;=&nbsp;10.1.20.21

</code>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Tue, 19 Jan 2010 17:24:35 -0600</pubDate>
            <category>gearman</category>
            <category>memcached</category>
            <category>mysql</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/php-autoloading</guid>
            <title>Autoloading for fun and profit</title>
            <link>http://brian.moonspot.net/php-autoloading</link>
            <description><![CDATA[So, as I stated in a <a href="http://brian.moonspot.net/php-code-organization">previous
post</a>, the code base here at dealnews is going through some
changes.&nbsp; I have been working heavily on those changes since
then.&nbsp; Testing and benchmarking to see what works best. One of
those changes is the heavy use of <a href="http://php.net/manual/en/language.oop5.autoload.php">autoloading</a>.&nbsp;<br>

<br>
During the holidays, I always like to read the <a href="http://phpadvent.org/2009">PHP Advent</a>.&nbsp; One of the posts
this year was by <a href="http://marcelesser.wordpress.com/">Marcel
Esser</a> titled <em><a href="http://phpadvent.org/2009/you-dont-need-all-that-by-marcel-esser">You
Don’t Need All That</a></em>. It was a great post and echos many
things I have said about PHP and web development. In his post,
Marcel benchmarks the difference between using an autoloader and
using straight require statements. I was not surprised by the
result. The autoloading overhead and class overhead is well known
to me. It is one thing that kept me from using any heavy OOP (we
banned classes on our user facing pages for a long time) in PHP 4
and PHP 5.0. It has gotten a lot better however. Class overhead is
very, very small now. Especially when using it as a namespacing for
static functions. However, there is one word of caution I would
like to add to his statements. When you use require/include
statements instead of autoloading, you end up with a file like
this:<br>

<code>
&lt;?php<br>
<br>
require "DB.php";<br>
require "Article.php";<br>
<br>
<br>
function myfunc1() {<br>
&nbsp;&nbsp;&nbsp;&nbsp;DB::somemethod();<br>
}<br>
<br>
function myfunc2(){<br>
&nbsp;&nbsp;&nbsp;&nbsp;Article::somemethod();<br>
}<br>
<br>
?&gt;</code>That file needs to require two files, but each one is only
needed by one function in the file.&nbsp; This is the dilemma we
have found ourselves in.&nbsp; We have a file that is filled with
functions for building, taking apart, repairing, fetching, or
anything else you can think to do with a URL. So, at the top of
that file are 13 require statements. This all happened organically
over time. But, now we are in a situation where we load lots of
files that may not even be needed to begin with. By moving to an
autloading system, we will only include the code we need. This
saves cycles and file IO.<br>
<br>
Again, Marcel's post was dead on. Our front end is written with
multiple entry points.&nbsp; We use auto_prepend files to do any
common work that all requests need (sessions, loading the
application settings, etc).&nbsp; The front page of <a href="http://dealnews.com/">dealnews.com</a> is about 600 lines of PHP
that does the job as quickly as possible. But, we are moving it to
use autoloaded code because its require list has grown larger than
I would like and some of those requires are not always "required"
to generate the page.<br>
<br>
One point Marcel did make was about how modern MVC systems are part
of the problem. We don't have a highly structured traditional MVC
layout of our code. We use a very wide, flat directory structure
rather than deep nesting of classes and objects. We also don't do a
lot of overloading. Maybe 1% of our classes extend another and
never more than one deep. All that makes for much quicker loading
objects vs. some of the packaged frameworks like Zend
Framework.<br>
<br>
So, as Marcel warned, be aware of both your use of autoloading and
require statements. Both can be bad when used the wrong way.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Fri, 08 Jan 2010 09:44:47 -0600</pubDate>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/microsoft-bing-commercials-lie</guid>
            <title>Bing ads are such bull crap</title>
            <link>http://brian.moonspot.net/microsoft-bing-commercials-lie</link>
            <description><![CDATA[Have you see these <a href=
"http://www.youtube.com/watch?v=i1AwFY6MuwE">Bing ads</a>? The
insinuate that web search gives you a lot of crap. But, that Bing
can cure that problem. Really? One simple question Bing:<br>

<h2>
    How big is the sun?
</h2>

<h4>
    Google
</h4>
Google tells me the mass right off the bat. Neat. The following
links are all very relevant too.<br>
<br>
<a href=
"http://www.google.com/search?q=how+big+is+the+sun%3F"><img alt=""
style="border: 1px solid black;" src=
"http://content.screencast.com/users/brianlmoon/folders/Jing/media/5ba02f7b-2aac-49ba-99d2-a6e4255a7f43/00000036.png">
</a><br>
<br>

<h4>
    Yahoo
</h4>
Yahoo gives me an interesting alternate query. The links are all
relevant too.<br>
<br>
<a href=
"http://search.yahoo.com/search?p=how+big+is+the+sun%3F"><img alt=
"" style="border: 1px solid black;" src=
"http://content.screencast.com/users/brianlmoon/folders/Jing/media/7e0aa7df-beb8-44f8-9a0b-ea4d96ae11f5/00000037.png">
</a><br>
<br>

<h4>
    Bing
</h4>
Bing starts well by suggesting some queries.<br>
<br>
<img alt="" style="width: 627px;" src=
"http://content.screencast.com/users/brianlmoon/folders/Jing/media/7d739a9c-9eb8-496e-a67b-e00351243262/00000038.png">
<br>
<br>
But, it soon falls apart IMO.<br>
<br>
<a href=
"http://www.bing.com/search?q=how+big+is+the+sun%3F"><img alt=""
style="border: 1px solid black; width: 650px; height: 300px;" src=
"http://content.screencast.com/users/brianlmoon/folders/Jing/media/6d4ba1d3-b502-4a0e-8145-09179ce0f3de/00000039.png">
</a><br>
<br>
Big Red Sun? A garden design company? That is the most relevant?
Really? The third result is way off too. Their related searches
clearly seem to indicate that Bing understands what I am looking
for, but their results fail badly. Get the log out of your eye
Bing.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 21 Dec 2009 12:03:08 -0600</pubDate>
            <category>search</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/php-code-organization</guid>
            <title>Code Organization Dilemma</title>
            <link>http://brian.moonspot.net/php-code-organization</link>
            <description><![CDATA[So, we have been building up our code library at <a href=
"http://dealnews.com/">dealnews</a> for 9 years. It was started at
the end of PHP3 and the beginning of PHP4. So, we did not have
autoloading, static functions, and all that jazz. Classes had lots
of overhead in early PHP4 so we started down a pure procedural road
in 2000. And for a long time, it was very maintainable. We had 2 or
3 developers for most of this time. We now have 5 or 6 depending on
whether we have contractors. There are starting to be too many
files and too many functions. We find ourselves adding new files
when some new function is created instead of adding it to an
existing file because we don't want to have huge files with 100
functions in them. File names and function names are getting longer
and more ambiguous. For example, we have a file called
url_functions.php. It contains functions to generate URLs for
different types of pages on the site, functions to fetch URLs from
the web and functions to parse URLs from an article. Those probably
don't all belong in one file. But, they got nickle and dimed in
there over time. So, now, we are inclined to not add anything to
that file and make new files for new semi-URL related functions.
Ugh.<br>
<br>
It is time to start thinkinb about a reorganization. There are
1,900+ functions in 400+ files in our code library. This is just
our library. This does not include the code that actually builds a
page and generates output. It does not include our cron jobs or
system administration scripts. Yeah, that is a lot. So, where do we
go from here? Some things are easy to do. For example, we have a
file called string.php. Most all the functions in that file can
easily be moved a String class with static functions that can be
accessed via an autoloader.<br>
<br>
Then we have the various ways we deal with the articles on the web
site. I have <a href=
"http://brian.moonspot.net/2007/06/23/caching-and-patience/">written</a>
<a href=
"http://brian.moonspot.net/2007/08/29/out-with-cluster-hello-replication/">
about</a> our front end vs. back end system before. What this means
for our code base is that we have two ways to deal with an article.
One is in our highly relational backend system. The other is in our
optimized front end database servers. So, one Article object won't
really do. We already have an Article object that serves as an ORM
interface for the backend. To access the front end data, we
currently have a library of functions (fetch_article for a single,
fetch_articles for a set, etc.) but it does not fit with an
autoloading environment. It also is not related to the object (the
article) and is associated with where the data is stored. New
developers don't grok the server infrastructure, so the code
organization may not make sense to them. We have about 10 different
objects that need both a back end and front end interface.<br>
<br>
On the other hand, I really don't want to end up with a class named
FrontEndArticle and BackEndArticle. Much less do we want to have
stuff like BackEnd_Article where the file is actually in
BackEnd/Article.php somewhere. The verbosity becomes overwhelming
and hard to read, IMO.<br>
<br>
So, what are others doing with huge code bases? I see lots of
projects with 100 or so functions/methods in 20-30 files.&nbsp;
Frameworks have it easy because they don't have a CEO that wants
something on this one page to be different than it is on every
other page where that data is used. We have to deal with those
types of hacks in an elegant way that can be maintained.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Wed, 18 Nov 2009 08:00:00 -0600</pubDate>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/forums-are-crap-help-us</guid>
            <title>Forums are crap. Can we get some help?</title>
            <link>http://brian.moonspot.net/forums-are-crap-help-us</link>
            <description><![CDATA[Amy Hoy has written a blog post about why <a href=
"http://sweatyd.posterous.com/forums-are-crap">forums are crap</a>.
And she is right. Forum software does not always do a good job of
helping people communicate. I have worked with Amy. She did a great
analysis of <a href="http://dealnews.com/">dealnews.com</a> that
led to our new design. So, she is not to be ignored.<br>
<br>
However, as a software developer (<a href=
"http://www.phorum.org/">Phorum</a>), I see a lot of problems and
no answers.&nbsp; And it is not all on the software.&nbsp; Web site
owners use forums to solve problems that they really, really suck
at.&nbsp; Ideally, every web site would be very unique for their
audience.&nbsp; They would use a custom solution that fits a number
of patterns that best solves their problem.&nbsp; However, most web
site owners don't want to take the time to do such things.&nbsp;
They want a one stop, drop in solution. See the monolith that is
vBulletin, scary.<br>
<br>
And what if a forum is the best solution? Well, software
developers, in general, are not good designers. They don't think
like normal people. And they don't see their applications as a
whole, but as pieces that do jobs. The forum software market has
been run by software developers for over 10 years. Most of them all
are still copies of what <a href=
"http://en.wikipedia.org/wiki/UBB.classic">UBB</a> was 13 years
ago. And software (like Phorum) that has tried to be different is
shunned by the online communities of the world because they don't
work/look/feel like every other forum software on the planet.<br>
<br>
So, as software developers, what are we to do? We want to make
great software. We want to help our users help their users. But,
what we have been doing for 10+ years has only been adequate. As
the leader of an open source forum software project, I am open to
any and all ideas.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 12 Oct 2009 10:01:44 -0500</pubDate>
            <category>mysql</category>
            <category>phorum</category>
            <category>php</category>
            <category>usability</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/yui-carousel</guid>
            <title>Custom carousel with YUI and OOCSS.org</title>
            <link>http://brian.moonspot.net/yui-carousel</link>
            <description><![CDATA[YUI has a built in <a href=
"http://developer.yahoo.com/yui/carousel/">carousel widget</a>.
However, it requires fixed widths for all the parts. That does not
fit well in a liquid CSS layout. In particular, we have to support
people using large fonts at the OS level and large font settings in
their browsers. I did not want for our carousel to break down in
these cases. The built in YUI widget does. See this <a href=
"http://www.screencast.com/users/brianlmoon/folders/Jing/media/72960e7d-0639-4ce8-a272-a1cef264d143">
normal sized screen shot</a> versus one with <a href=
"http://www.screencast.com/users/brianlmoon/folders/Jing/media/9988ee85-ab55-4b09-9c39-34a88c6fd6cc">
large fonts</a>. Now look at dealnews with <a href=
"http://screencast.com/t/CfcBpRXrcXfQ">normal fonts</a> and
<a href="http://www.screencast.com/users/brianlmoon/folders/Jing/media/5b1886a6-5797-425d-9695-e7dc2d8cd050">
large fonts</a>.<br>
<br>
So, I decided to make my own using YUI and the grid CSS from
<a href="http://oocss.org/">Object-Oriented CSS</a>.&nbsp; You can
see my working example with some explination <a href=
"http://brian.moonspot.net/yui_carousel/action.html">here</a>.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Fri, 09 Oct 2009 15:52:19 -0500</pubDate>
            <category>css</category>
            <category>html</category>
            <category>javascript</category>
            <category>yui</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/what-is-memcached</guid>
            <title>Memcached: What is it and what does it do?</title>
            <link>http://brian.moonspot.net/what-is-memcached</link>
            <description><![CDATA[I spoke at <a href="http://cw.mtacon.com/">CodeWorks</a> in
Atlanta, GA this week.&nbsp; I totally dropped the ball promoting
it on my blog.&nbsp; It was a neat venue.&nbsp; Rather than a large
conference they are doing a traveling show.&nbsp; Seven cities in
14 days.&nbsp; Many of the presenters are working in every
city.&nbsp; Crazy.&nbsp; I was just in Atlanta.&nbsp; It is close
to home and easy for me to get to.<br>
<br>
I spoke about <a href=
"http://code.google.com/p/memcached/">memcached</a>.&nbsp; I tried
to dig a bit deeper into how memcached works.&nbsp; On the mailing
list we get a lot of new people that make assumptions about
memcached.&nbsp; Most talks I have seen focus on why caching is
good, how to use memcached, the performance gain.&nbsp; I kind of
assumed everyone knew that stuff already.&nbsp; I guess you could
say I gave a talk that was the real FAQs of the project.<br>
<br>
Here are the slides.&nbsp; <a href=
"http://twitter.com/Derickr">Derick Rethans</a> took video of the
talk.&nbsp; When he gets that online I will add it to this
post.<br>
<br>

<div style="width: 425px; text-align: left;" id="__ss_2097515">
    <a style=
    "margin: 12px 0pt 3px; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 14px; line-height: normal; font-size-adjust: none; font-stretch: normal; display: block; text-decoration: underline;"
    href=
    "http://www.slideshare.net/brianlmoon/memcached-what-is-it-and-what-does-it-do-2097515"
    title="Memcached: What is it and what does it do?">Memcached:
    What is it and what does it do?</a><object style="margin: 0px;"
    width="425" height="355">
        <param name="movie" value=
        "http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=memcached-090930111655-phpapp02&amp;stripped_title=memcached-what-is-it-and-what-does-it-do-2097515">
        <param name="allowFullScreen" value="true">
        <param name="allowScriptAccess" value="always">
        <embed src=
        "http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=memcached-090930111655-phpapp02&amp;stripped_title=memcached-what-is-it-and-what-does-it-do-2097515"
        type="application/x-shockwave-flash" allowscriptaccess=
        "always" allowfullscreen="true" width="425" height="355">
    </object>
    <div style=
    "font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;">
    View more <a style="text-decoration: underline;" href=
    "http://www.slideshare.net/">documents</a> from <a style=
    "text-decoration: underline;" href=
    "http://www.slideshare.net/brianlmoon">Brian Moon</a>.
    </div>
</div>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Wed, 30 Sep 2009 11:49:39 -0500</pubDate>
            <category>memcached</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/wordcraft-0-10-available</guid>
            <title>Wordcraft 0.10 available</title>
            <link>http://brian.moonspot.net/wordcraft-0-10-available</link>
            <description><![CDATA[The latest package of <a href=
"http://brian.moonspot.net/what-is-wordcraft-">Wordcraft</a>, the
PHP/MySQL based blog software that runs this site, is available for
<a href=
"http://code.google.com/p/wordcraft/downloads/list?can=3">download
from Google Code</a>.&nbsp; Just some minor bug fixes and cosmetic
stuff.&nbsp; Its getting a little use in the wild.&nbsp; That is
always fun to see.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 10 Aug 2009 00:12:20 -0500</pubDate>
            <category>mysql</category>
            <category>php</category>
            <category>wordcraft</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/php-fork</guid>
            <title>Forking PHP!</title>
            <link>http://brian.moonspot.net/php-fork</link>
            <description><![CDATA[We use PHP everywhere in our stack. For us, it makes sense because
we have hired a great staff of PHP developers. So, we leverage that
talent by using PHP everywhere we can.
<p>
    One place where people seem to stumble with PHP is with long
    running PHP processes or parallel processing. The <a href=
    "http://us.php.net/pcntl">pcntl extension</a> gives you the
    ability to fork PHP processes and run lots of children like
    many other unix daemons might. We use this for various things.
    Most notably, we use it run <a href=
    "http://gearman.org/">Gearman</a> worker processes. While at
    the OReilly Open Sourc Convention in 2009, we were asked about
    how we pulled this off. So, we are releasing the two scripts
    that handle the forking and some instructions on how we use
    them.
</p>

<p>
    This is not a detailed post about long running PHP
    scripts.&nbsp; Maybe I can get to the dos and don'ts of that
    another time.&nbsp; But, these are the scripts we use to manage
    long running processes.&nbsp; They work great for us on
    Linux.&nbsp; They will not run on Windows at all.&nbsp; We also
    never had any trouble running them on Mac OS X.
</p>

<p>
    The first script, prefork.php, is for forking a given function
    from a given file and running <em>n</em> children that will
    execute that function. There can be a startup function that is
    run before any forking begins and a shutdown function to run
    when all the children have died.
</p>

<p>
    The second script, prefork_class.php, uses a class with defined
    methods instead of relying on the command line for function
    names. This script has the added benefit of having functions
    that can be run just before each fork and after each fork. This
    allows the parent process to farm work out to each child by
    changing the variables that will be present when the child
    starts up. This is the script we use for managing our Gearman
    workers. We have a class that controls how many workers are
    started and what functions they provide. I may release a
    generic class that does that soon. Right now it is tied to our
    code library structure pretty tightly.
</p>

<p>
    We have also included two examples. They are simple, but do
    work to show you how the scripts work.
</p>

<p>
    You can download the code from the <a href=
    "http://dealnews.com/developers/">dealnews.com developers'
    page</a>.
</p>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Thu, 23 Jul 2009 13:17:42 -0500</pubDate>
            <category>gearman</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/att-or-apple-iphone-issue</guid>
            <title>What is the problem? AT&amp;amp;T or Apple?</title>
            <link>http://brian.moonspot.net/att-or-apple-iphone-issue</link>
            <description><![CDATA[So, I told you how <a href=
"http://brian.moonspot.net/att-and-iphone-is-bad">AT&amp;T messed
up my account</a> when I ordered the new iPhone.&nbsp; Well, I go
the new one on Friday via FedEx.&nbsp; I then left for Velocity in
San Jose, CA on Sunday.&nbsp; The phone was not activated when I
left.&nbsp; So, I had to take my old iPhone and my new iPhone 3GS
with me.&nbsp; Grrrr.&nbsp; On top of that, I had to keep them both
on me because afaik, as soon as the new one started working, the
old one would not.&nbsp; Double Grrrrrr.<br>
<br>
I was blaming AT&amp;T for this over and over.&nbsp; I tried
calling them on Saturday and the guy on the phone said he was
instructed to tell me to go to an AT&amp;T store or an Apple
Store.&nbsp; I did not have time to find an AT&amp;T store.&nbsp; I
tried the Apple store as we were having dinner right near it.&nbsp;
But, the wait was an hour!!! Triple Grrrrrrr.&nbsp;<br>
<br>
So, on Sunday night, I got this email from Apple:<br>

<blockquote>
    Dear Apple Customer,<br>
    <br>
    Thank you for your recent Apple Store order. We appreciate your
    patience and apologize for the inconvenience caused by the
    delay in your iPhone activation.<br>
    <br>
    We are still resolving the issue that was encountered while
    activating your iPhone with AT&amp;T. Unfortunately, due to
    system issues and continued high activation volumes, this could
    take us up to an additional 48 hours to complete.<br>
    <br>
    On Monday, you'll receive an email from Apple with an iTunes
    Store credit in the amount of $30. We hope you will enjoy this
    gift and accept our sincere apologies for the inconvenience
    this delay has caused.<br>
    <br>
    Thank you for choosing Apple.<br>
    <br>
    Sincerely,<br>
    Apple Online Store Team<br>
</blockquote>
So, whose fault is this?&nbsp; Is it Apple or AT&amp;T?&nbsp; I had
been assuming AT&amp;T all along.&nbsp; But, Apple is giving me the
credit.<br>
<br>
On Monday morning, at about 11:30CDT, my phone was activated.&nbsp;
That is about 62 hours after I hooked it up to iTunes.&nbsp; The
phone is great.&nbsp;<br>
<br>
I guess I should listen to Louis CK says and just be happy that the
future is here and quit bitching.<br>
<br>
<object height="344" width="425">
    <param name="movie" value=
    "http://www.youtube.com/v/jETv3NURwLc&amp;hl=en&amp;fs=1&amp;">
    <param name="allowFullScreen" value="true">
    <param name="allowscriptaccess" value="always">
    <embed src=
    "http://www.youtube.com/v/jETv3NURwLc&amp;hl=en&amp;fs=1&amp;"
    type="application/x-shockwave-flash" allowscriptaccess="always"
    allowfullscreen="true" height="344" width="425">
</object>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Fri, 26 Jun 2009 14:20:59 -0500</pubDate>
            <category>apple</category>
            <category>iphone</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/att-and-iphone-is-bad</guid>
            <title>AT&amp;amp;T is a bleepity bleeping bleep</title>
            <link>http://brian.moonspot.net/att-and-iphone-is-bad</link>
            <description><![CDATA[So, on June 19th, the <a href="http://www.apple.com/iphone/">new
iPhone</a> comes out. I have a first generation iPhone.&nbsp; I
have loved it.&nbsp; My area is not well covered by 3G so I did not
bother upgrading.&nbsp; But, my two year contract is up next month
and just the other day I dropped and cracked my iPhone
screen.&nbsp; So, this is a good time to upgrade.<br>
<br>
I ordered my new phone via the Apple web site.&nbsp; It took me
through a wizard that checked my AT&amp;T account and showed me the
options for upgrading.&nbsp; That all went smooth.&nbsp; This all
took place on Thursday, June 11, 2009.&nbsp; Well, at 11AM on
Saturday, June 13th, something happened to my account.&nbsp; On my
account are 4 phones.&nbsp; Mine, my wifes and my two oldest
kids.&nbsp; My daughter says from the back seat (did I mention we
are on our way to the beach for a week?) "That took them long
enough.&nbsp; I got a welcome text from AT&amp;T."&nbsp; She has
had her phone since Christmas.&nbsp; Later I noticed I had no data
connection.&nbsp; Just bars.&nbsp; I was getting calls.&nbsp; Then
later my wife commented that no one was returning her SMS
messages.&nbsp; So, we tried sending some to each other.&nbsp;
Nothing. My son sees he got a welcome SMS too. OMG, wtf did
AT&amp;T do?!?!?!?<br>
<br>
We are driving (I mentioned that I think) and have time on our
hands, so my wife calls them about it all.&nbsp; Sure enough, they
claim that "someone" removed our family unlimited text message plan
from the account.&nbsp; Well, that someone would be AT&amp;T.&nbsp;
See, I had reduced my iPhone to the lower plan a while back because
I was getting the family unlimited text messaging plan when I added
my kids phones.&nbsp; But, the new iPhone only has one data plan
available.&nbsp; It's a $30/month unlimited data plan.&nbsp;
Apparently, me changing the data plan for the new iPhone that is
not even shipped yet removed all text messaging for my whole
family.&nbsp; The lady claims to have it fixed so we hang up.<br>
<br>
Time passes and I still don't have and EDGE connection.&nbsp; My
daughter tries to send a MMS picture and is blocked. We call
back.&nbsp; Apparently the brilliant person my wife talked to the
first time added a pay per SMS feature and NO MMS OR DATA!&nbsp;
ARGHHH!!!!&nbsp; We tell the lady, "Look, just put it back like it
was on the last bill."&nbsp; That worked, we were happy with
that.&nbsp; A few minutes later I had data and we could send
pictures again.<br>
<br>
So, you would think it is over.&nbsp; But, apparently I don't have
voice mail.&nbsp; And now I am really wondering what will happen
when I activate my new iPhone this week.&nbsp; Be thinking about me
as I am sure it will hose my account again.&nbsp; And I leave town
on Sunday to attend <a href=
"http://en.oreilly.com/velocity2009">Velocity</a>.&nbsp;<br>
<br>
Please, please, two years from now, when my contract is up, please
let Verizon have the iPhone.&nbsp; Our accounts payable people at
dealnews don't like their billing practices, but I have never had a
customer service issue with them and their network is the best
ever.<br>
<br>
Some interesting things to note:<br>

<ol>
    <li>You can't buy or activate an iPhone without a data
    plan.&nbsp; But, clearly they had mine working without one.
    </li>

    <li>They turned off SMS for my whole family, but, the first
    thing my kids got after they turned it off was an SMS that I
    bet they would have charged us for.
    </li>

    <li>We could not send MMS at all for our whole account after
    the new iPhone was purchased.&nbsp; It is well known that
    AT&amp;T is not allowing MMS on the new iPhone yet.&nbsp; Guess
    they control this at the account level?
    </li>
</ol>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Wed, 17 Jun 2009 00:29:38 -0500</pubDate>
            <category>apple</category>
            <category>fail</category>
            <category>iphone</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/pecl-memcache-mac-osx</guid>
            <title>Building PECL/memcache on Mac OS X</title>
            <link>http://brian.moonspot.net/pecl-memcache-mac-osx</link>
            <description><![CDATA[My coworker Rob ran into an issue building the PECL/memcache
extension on his Mac.&nbsp; He did <a href=
"http://codelemur.wordpress.com/2009/05/30/pecl-memcache-and-php-on-mac-os-x-leopard/">
find the solution</a> however.&nbsp; You can read and leave
comments on his blog.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Sun, 31 May 2009 22:23:29 -0500</pubDate>
            <category>apache</category>
            <category>apple</category>
            <category>memcached</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/using-the-glammp-stack</guid>
            <title>The rise of the GLAMMP stack</title>
            <link>http://brian.moonspot.net/using-the-glammp-stack</link>
            <description><![CDATA[First there was <a href=
"http://en.wikipedia.org/wiki/LAMP_%28software_bundle%29">LAMP</a>.&nbsp;
But are you using GLAMMP?&nbsp; You have probably not heard of it
because we just coined the term while chatting at work.&nbsp; You
know LAMP (Linux, Apache, MySQL and PHP or Perl and sometimes
Python). So, what are the extra letters for?<br>
<br>
<strong>The G is for Gearman</strong> - <a href=
"http://www.gearman.org/">Gearman</a> is a system to farm out work
to other machines, dispatching function calls to machines that are
better suited to do work, to do work in parallel, to load balance
lots of function calls, or to call functions between languages.<br>
<br>
<strong>The extra M is for Memcached</strong> - <a href=
"http://www.danga.com/memcached/">memcached</a> is a
high-performance, distributed memory object caching system, generic
in nature, but intended for use in speeding up dynamic web
applications by alleviating database load.<br>
<br>
More and more these days, you can't run a web site on <em>just</em>
LAMP.&nbsp; You need these extra tools (or ones like them) to do
all the cool things you want to do.&nbsp; What other tools do we
need to work into the acronym?&nbsp; <a href=
"http://www.postgresql.org/">PostgreSQL</a> replaces MySQL in lots
of stacks to form LAPP.&nbsp; I guess <a href=
"http://drizzle.org/">Drizzle</a> may replace MySQL in some stacks
soon.&nbsp; For us, it will likely be <a href=
"http://brian.moonspot.net/2008/07/24/156/">added to the
stack</a>.&nbsp; Will that make it GLAMMPD?&nbsp; We need more
vowels!&nbsp; If you are starting the next must use tool for
running web sites on open source software, please use a vowel for
the first letter.<br>
<br>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Fri, 22 May 2009 11:34:39 -0500</pubDate>
            <category>apache</category>
            <category>gearman</category>
            <category>linux</category>
            <category>memcache</category>
            <category>mysql</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/finding-register-globals</guid>
            <title>Is there a program for finding uses of register_globals?</title>
            <link>http://brian.moonspot.net/finding-register-globals</link>
            <description><![CDATA[register_globals is going way in PHP6.&nbsp; That is fine with
me.&nbsp; Super globals are cool and I have taken to using <a href=
"http://php.net/filter_input_array">filter_input_array</a> these
days anyhow.&nbsp; However, our code base is now 10+ years old at
dealnews.&nbsp; Most of the forward facing code was completely
rewritten in the last couple of years due to architecture
changes.&nbsp; Many new projects had register_globals turned off
via php_admin_flag in Apache.&nbsp; So, that area is not that big
of a problem.&nbsp; However, our internal admin areas have not all
be rewritten because, well frankly, they still work.&nbsp; Yeah,
stuff written for PHP4 in 2000 is still working.&nbsp; KISS helps a
lot with that.&nbsp; But, this code, somewhere in there, may still
be relying on register_globals.&nbsp; Now, we could go line by line
and try and fix it.&nbsp; But, it seems like a program could be
written to do this job.&nbsp; I mean, I use jEdit and it can
highlight unset vars using the PHPParserPlugin just fine.&nbsp; I
bet Zend IDE can do the same.&nbsp; Has anyone written such a tool
for the command line?&nbsp; There will be false positives I
know.&nbsp; Things like passing a variable by reference to a
function would look like a use before set.&nbsp; But, I can deal
with those if I don't have to go line by line through tons of old
code.&nbsp; What would the rules look like for such an
animal?&nbsp; This would be a great project to get off the ground
before PHP6 hits.&nbsp; Ideally you could provide a list of
variables for it to ignore.&nbsp; We have some globals we set up in
prepends and includes.<br>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Fri, 15 May 2009 12:38:58 -0500</pubDate>
            <category>php</category>
            <category>security</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/speaking-velocity-2009</guid>
            <title>Scaling for the Expected and Unexpected - Speaking at Velocity</title>
            <link>http://brian.moonspot.net/speaking-velocity-2009</link>
            <description><![CDATA[Last year I was surprised to be <a href=
"http://brian.moonspot.net/2008/06/18/did-you-know-i-am-going-to-be-at-velocity/">
going to Velocity</a>.&nbsp; Read the post, it was an
adventure.&nbsp; But, I <a href=
"http://brian.moonspot.net/2008/07/01/velocity-conference-roundup/">
really like the conference</a>.&nbsp; It is the perfect conference
for me.&nbsp; While a good majority of my work is done coding
PHP/MySQL apps, I tend to focus on architecture, frameworks,
performance and that kind of stuff.&nbsp; So, a web performance and
operations conference is just perfect.<br>
<br>
Last year, I was on a panel with <a href=
"http://en.oreilly.com/velocity2008/public/schedule/detail/4762">some
great guys</a>.&nbsp; I was able to share just a bit about my
experience dealing with the instant success of a web site.&nbsp;
This year, my proposal was accepted to talk more about dealing with
success of a web site.&nbsp; The talk will be focused on my
experience at <a href="http://dealnews.com/">dealnews.com</a> and
from working with power users for <a href=
"http://www.phorum.org/">Phorum</a>.&nbsp; Here is the summary:<br>

<blockquote>
    <div>
        <p>
            Lots of people talk about scaling and performance. But,
            are they preparing for all the things that could
            happen? There are multiple problems and there is not
            one solution to solve them all.
        </p>

        <p>
            Everything is running fine and <span class=
            "caps">BAM</span>! – your site is linked from the front
            page of Yahoo! What do you do? How can you handle that
            sudden rush of traffic. Requests per second are running
            5x normal levels. Servers have <span class=
            "caps">CPU</span> spikes. Daemons are hitting the
            maximums. You are running out of bandwidth. How could
            you have been prepared for this? What are the tools and
            techniques for this type of sudden rush?
        </p>

        <p>
            Or, lets say you have just come out of a meeting where
            everyone discovered that your site is growing in
            traffic 70% – 80% year over year. That means that 1
            million page views this month will be nearly 3 million
            this time in 2 years. How can you plan for that? You
            don’t want to redesign the whole architecture every 2
            years. What methods could be used to deal with this
            constant long term growth?
        </p>

        <p>
            While there is no magic bullet for either of these
            scenarios, there are techniques used by many sites out
            there to help you get through these situations. This
            session will cover some of these techniques and talk
            about their pros and cons.
        </p>
    </div>
</blockquote>

<div>
    <p>
        I must admit, this if the first time since 2000 that I am a
        little intimidated to speak at a conference.&nbsp; The
        people that present and attend Velocity are so
        awesome.&nbsp; I just hope I don't disappoint.
    </p>
</div>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Thu, 07 May 2009 11:57:27 -0500</pubDate>
            <category>mysql</category>
            <category>php</category>
            <category>velocity</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/net-gearman-php-5.2.9</guid>
            <title>Net::Gearman and PHP 5.2.9</title>
            <link>http://brian.moonspot.net/net-gearman-php-5.2.9</link>
            <description><![CDATA[I just discovered an incompatibility between <a href=
"http://pear.php.net/package/Net_Gearman/">Net Gearman</a> and PHP
5.2.9+.&nbsp; json_decode was <a href=
"http://bugs.php.net/bug.php?id=45989">changed in 5.2.9</a> to
return NULL on invalid JSON strings.&nbsp; Previously, the bare
string had been returned if it was not valid JSON.&nbsp; This was
nice in a way as you could pass a scalar string to json_decode and
not worry about it.&nbsp; But, in reality, it would make debugging
a nightmare for JSON.<br>
<br>
I have updated <a href=
"http://github.com/brianlmoon/net_gearman/tree/master">my github
fork</a> and requested a pull into the <a>main branch</a>.&nbsp;
Once that is done a new PEAR release can be done.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Tue, 21 Apr 2009 12:48:53 -0500</pubDate>
            <category>gearman</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/dont-use-the-die-function</guid>
            <title>The death of die()</title>
            <link>http://brian.moonspot.net/dont-use-the-die-function</link>
            <description><![CDATA[I am calling it.&nbsp; The death of the PHP <a href=
"http://www.php.net/die">die</a> function.&nbsp; Now, I have no
actual authority to do so.&nbsp; My PHP CVS karma does not extend
that far.&nbsp; And I doubt it will actually get removed despite it
being nothing more than an alias for <a href=
"http://www.php.net/exit">exit</a> now.<br>
<br>
No, what I would like to call a death to is the usage of die such
as:<br>
<br>
<code>$conn = mysql_connect($server, $user, $pass) or die("Could
not connect to MySQL, but needed to tell the whole
world");</code><br>
I don't know who thought that particular usage was good, but they
need to .... no, that is harsh.&nbsp; I just really wish they had
never done that.<br>
<br>
So, what should you use?&nbsp; Well, there are a couple of options
depending on what context you are working in and whether or not the
failure is actually catastrophic.<br>
<br>
<strong>Exceptions</strong><br>
<br>
If you are using OOP in your PHP code, <a href=
"http://www.php.net/exceptions">Exceptions</a> are the logic choice
for dealing with errors.&nbsp; I have mixed feelings about
them.&nbsp; But, it has more to do with the catching of exceptions
than the throwing of them.&nbsp; If you are going to live in a
world of exceptions, please catch them and provide useful error
messages.&nbsp; The PHP world is not too bad about that, but I have
read too many Java error logs full of huge, verbose exception dumps
in my life already.&nbsp; Please don't follow that technique in
PHP.<br>
<br>
<strong>trigger_error</strong><br>
<br>
The function <a href=
"http://www.php.net/trigger_error">trigger_error</a> is quite
handy.&nbsp; It allows you, a common PHP coder, to create errors
just like the core system.&nbsp; So, the error messages are
familiar to anyone that is used to seeing PHP errors.&nbsp; So, if
your system is configured to log errors and not display them,
errors from trigger_error will be treated the same as built in
errors.<br>
<br>
Also, errors thrown with trigger_error are caught by a custom
<a href="http://www.php.net/set_error_handler">error handler</a>
just like built in errors.&nbsp; They can be logged, printed,
whatever you want from that error handler, just like normal PHP
errors.&nbsp; There are even several levels of errors you can raise
like notices, warnings, errors, and even deprecated.&nbsp; Again,
just like the built in PHP errors.<br>
<br>
<strong>FATAL Errors</strong><br>
<br>
trigger_error is also the most suitable way, IMO, to end a script
immediately.<br>
<br>
<code>$conn = mysql_connect($server, $user, $pass);<br>
if(!$conn) {<br>
&nbsp;&nbsp;&nbsp; trigger_error("Could not connect to MySQL
database.", E_USER_ERROR);<br>
}</code><br>
Now that will not be told to the whole world if you have
display_errors set to Off as you should in any production
environment.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Thu, 16 Apr 2009 23:13:42 -0500</pubDate>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/wordcraft-0-9-1-available</guid>
            <title>Wordcraft 0.9.1 available</title>
            <link>http://brian.moonspot.net/wordcraft-0-9-1-available</link>
            <description><![CDATA[There are several key changes in Wordcraft 0.9.1. The two big
things are:<br>

<ul>
    <li>
        <span>Tokens on post forms in the admin to help ward off
        <a href=
        "http://shiflett.org/articles/cross-site-request-forgeries">
        CSRF attacks</a>.&nbsp;&nbsp;</span>
    </li>

    <li>
        <span>Database schema updates automated.</span>
    </li>
</ul>
<span>The first comes as a result of us doing the same work on
Phorum recently.&nbsp; I realized I needed the same protection in
Wordcraft.&nbsp; The second was done out of neccesity as I changed
the datetime fields in the database schema into int fields.&nbsp;
Not sure why I ever made them datetime fields.&nbsp; Unix
timestamps are much easier to work with.&nbsp; It saves many
strtotime() calls and will make eventual time zone settings much
easier to implement.<br>
<br>
In addition to those two big ones, there were some notable small
ones:<br></span>
<ul>
    <li>HTML 4.01 validation fixes
    </li>

    <li>Ensuring UTF-8 on all encoding function calls
    </li>

    <li>Protection against hitting the back button when writing a
    post (most annoying on Macs as the back button and the
    beginning of line keystroke is the same).
    </li>
</ul>
And there were other a few <a href=
"http://code.google.com/p/wordcraft/source/list">other bug
fixes</a>.<br>
<br>
I will or course need many more testers and users before I can ever
declare this software as stable.&nbsp; If you need a simple blog,
give it a try.<br>
<br>
<strong>About Wordcraft</strong><br>
Wordcraft aims to be a simple, lightweight blogging
application.&nbsp; Wordcraft is written exclusively for PHP 5+ and
MySQL 5.0+ using only the PHP mysqli extension, UTF-8, and HTML
4.01 to achieve that simpleness.<br>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Wed, 08 Apr 2009 08:00:00 -0500</pubDate>
            <category>mysql</category>
            <category>php</category>
            <category>wordcraft</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/mod-substitute-mod-proxy-problem</guid>
            <title>mod_substitute is cool.  But, be careful with mod_proxy</title>
            <link>http://brian.moonspot.net/mod-substitute-mod-proxy-problem</link>
            <description><![CDATA[For our development servers, we have always used output buffering
to replace the URLs (dealnews.com) with the URL for that
development environment.&nbsp; Where we run into problems is with
CSS and JavaScript.&nbsp; If those files contains URLs for images
(CSS) or AJAX (JS) the URLS would not get replaced.&nbsp; Our
solution has been to parse those files as PHP (on the dev boxes
only) and have some output buffering replace the URLs in those
files.&nbsp; That has caused various problems over the years and
even some confusion for new developers.&nbsp; So, I got to looking
for a different solution.&nbsp; Enter <span><a href=
"http://httpd.apache.org/docs/2.2/mod/mod_substitute.html">mod_substitute</a>
for Apache 2.2.</span><br>

<blockquote>
    <em><a href=
    "http://httpd.apache.org/docs/2.2/mod/mod_substitute.html">mod_substitute</a>
    provides a mechanism to perform both regular expression and
    fixed string substitutions on response bodies.</em> - Apache
    Documentation<br>
</blockquote>
Cool!&nbsp; I put in the URL mappings and VIOLA!&nbsp; All was
right in the world.<br>
<br>
Fast forward a day.&nbsp; Another developer is testing some new
code and finds that his XML is getting munged.&nbsp; At first we
blamed libxml because we had just been through an ordeal with a bad
combination of a libxml compile option and PHP a while back.&nbsp;
Maybe we missed that box when we fixed it.&nbsp; We recompiled
everything on the dev box but there was no change.&nbsp; So I
started to think what was recently different with the dev
boxes.&nbsp; So, I turn off mod_substitute.&nbsp; Dang, that fixed
it.&nbsp; I looked at my substitution strings and everything looked
fine.&nbsp; After cursing and being depressed that such a cool tool
was not working, I took a break to let it settle in my mind.<br>
<br>
I came back to the computer and decided to try a virgin Apache 2.2
build.&nbsp; I downloaded the source from the web site instead of
building from Gentoo's Portage.&nbsp; Sure enough, a simple test
worked fine.&nbsp; No munging.&nbsp; So, I loaded up the dev box
Apache configuration into the newly compiled Apache.&nbsp; Sure
enough, munged XML.&nbsp; ARGH!!<br>
<br>
Up until this point, I had configured the substitutions globally
and not in a particular virtual host.&nbsp; So, I moved it all into
one virtual host configuration.&nbsp; Still broken.<br>
<br>
A little more background on our config.&nbsp; We use mod_proxy to
emulate some features that we get in production with our F5 BIG-IP
load balancers.&nbsp; So, all requests to a dev box hit a mod_proxy
virtual host and are then directed to the appropriate virtual host
via a proxied request.&nbsp;<br>
<br>
So, I got the idea to hit the virtual host directly on its port and
skip mod_proxy.&nbsp; Dang, what do you know.&nbsp; It worked
fine.&nbsp; So, something about the output of the backend request
and mod_proxy was not playing nice.&nbsp; So, hmm.&nbsp; I got the
idea to move the mod_substitute directives into the mod_proxy
virtual hosts configuration.&nbsp; Tested and working fine.&nbsp;
So, basically, this ensures that the substitution filtering is done
only after the proxy and all other requests have been
processed.&nbsp; I am no Apache developer, so I have not dug any
deeper.&nbsp; I have a working solution and maybe this blog post
will reach someone that can explain it.&nbsp; As for
mod_substitute, here is the way my config looks.<br>
<br>
In the VirtualHost that is our global proxy, I have this:<br>
<br>
<code>FilterDeclare DN_REPLACE_URLS<br>
FilterProvider DN_REPLACE_URLS SUBSTITUTE resp=Content-Type
$text/<br>
FilterProvider DN_REPLACE_URLS SUBSTITUTE resp=Content-Type
$/xml<br>
FilterProvider DN_REPLACE_URLS SUBSTITUTE resp=Content-Type
$/json<br>
FilterProvider DN_REPLACE_URLS SUBSTITUTE resp=Content-Type
$/javascript<br>
FilterChain DN_REPLACE_URLS</code><br>
<br>
Elsewhere, in a file that is local to each dev host, I keep the
actual mappings for that particular host:<br>
<br>
<code>Substitute
"s|http://dealnews.com|http://somedevbox.dealnews.com|in"<br>
Substitute
"s|http://dealmac.com|http://somedevbox.dealmac.com|in"<br>
# etc....</code><br>
<br>
I am trying to think of other really cool uses for this.&nbsp; Any
ideas?]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Tue, 07 Apr 2009 20:03:22 -0500</pubDate>
            <category>apache</category>
            <category>html</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/best-practices-escape-html</guid>
            <title>Best practices for escaping HTML</title>
            <link>http://brian.moonspot.net/best-practices-escape-html</link>
            <description><![CDATA[I am working on <a href=
"http://code.google.com/p/wordcraft/">Wordcraft</a>, trying to get
the last annoying HTML validation errors worked out.&nbsp; Thinks
like ampersands in URLs.&nbsp; In doing so, I am asking myself
where the escaping should take place. In the case of Wordcraft,
there are several parts to it.<br>

<ol>
    <li>The code that pulls data from the database.&nbsp; Obviously
    not the right place.
    </li>

    <li>The code that formats data like dates and such.&nbsp; It
    also organizes data from several data sources into one nice
    tidy array.&nbsp; Hmm, maybe
    </li>

    <li>The parts of the code that set up the output data for the
    templates.
    </li>

    <li>The templates themselves.
    </li>
</ol>
Now, I am sure 1 is not the place.&nbsp; And I really would not
want 4 to be the place.&nbsp; That would make for some ugly
templating.&nbsp; Plus, the templates, IMO, should assume the data
is ready to be output.&nbsp; So, that leaves the code that does the
formatting and the code that does the data setup.<br>
<br>
Of those two, I guess the place to do this job is in the data
setup.&nbsp; Wordcraft has a $WCDATA array that is available in the
scope of the templates.&nbsp; I suppose anything that goes into
that array should be escaped as appropriate.<br>
<br>
I largely wrote this blog post as a <a href=
"http://headrush.typepad.com/creating_passionate_users/2005/01/rubberducking_a.html">
teddy bear exercise</a>.&nbsp; But, I am curious.&nbsp; Where and
when do you escape your data for use in HTML documents?]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Fri, 20 Mar 2009 22:55:00 -0500</pubDate>
            <category>html</category>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/enhanced-404-page</guid>
            <title>Enhance your 404 Pages with Google</title>
            <link>http://brian.moonspot.net/enhanced-404-page</link>
            <description><![CDATA[I was just poking around the <a href=
"https://www.google.com/webmasters/tools/">Google Webmaster
Tools</a> and came across a neat idea.&nbsp; Google has a snippet
of javascript you can <a href=
"http://www.google.com/support/webmasters/bin/answer.py?answer=93644">
put on your 404</a> error pages that will give the user more
information based on their indexing of your site.&nbsp; It can
offer a user things like a closest match to the URL they were
trying to find, an alternative URL, a link to the site's site map
and last but not least, a Google search box that searches the site
in question.&nbsp; You have to have your site setup in Webmaster
Tools to use it.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Thu, 12 Mar 2009 22:04:57 -0500</pubDate>
            <category>google</category>
            <category>http</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/html-vs-xhtml</guid>
            <title>HTML vs. XHTML and validation</title>
            <link>http://brian.moonspot.net/html-vs-xhtml</link>
            <description><![CDATA[There is no shortage on the <a href=
"http://www.google.com/search?q=html+vs+xhtml">pages</a> on the
internet that talk about <a href=
"http://www.w3.org/TR/html401/">HTML</a> vs. <a href=
"http://www.w3.org/TR/xhtml11/">XHTML</a>.&nbsp; The vast majority
of these (in the first few pages of Google) seem to favor
XHTML.&nbsp; I don't really have an agenda, so I thought I would
post my thoughts on the topic.<br>
<br>
I have stated on this blog that I use HTML 4.01
Transistional.&nbsp; I do so because it is easiest for me.&nbsp;
Some people argue that XHMTL is easier because there are set rules
and if you violate those rules, the documents will not
render.&nbsp; Is that a good thing?&nbsp; Perhaps my time in the
late 90's has made my mind work differently than newcomers to the
World Wide Web.<br>
<br>
The browser wars were ugly.&nbsp; And I mean <a href=
"http://www.donmouth.co.uk/web_design/browsermuseum/browsermuseum.html">
literally ugly</a>.&nbsp; If you wanted to do anything fancy, it
required lots of images or compromise.&nbsp; I learned early on
that it was ok that the spacing in IE on my PC was larger than IE
on the Mac.&nbsp; The fonts were all different sizes from browser
to browser and OS to OS.&nbsp; I learned that graceful fallback was
part of the web.&nbsp; Even now, dealnews.com looks "adequate" in
IE 6.&nbsp; I could make it look perfect.&nbsp; But, the declining
traffic from IE6 does not merit my time to fix the errors in IE
6.<br>
<br>
So, when I start thinking about HTML vs. XHTML, I want the more
flexible of the two.&nbsp; I find syntax like nowrap='nowrap' very
annoying in XHTML.&nbsp; Especially since I can't say
nowrap='yeswrap' and it mean anything.&nbsp; nowrap=1 I could
handle.&nbsp; But, no, it has to be nowrap='nowrap'.&nbsp;
Geez.<br>
<br>
Ok, ok, this is turning into an XHTML hate post.&nbsp; I don't want
to do that.&nbsp; There are some things about XHTML that I do
like.&nbsp; I like the self closing tags.&nbsp; My OCD (which I
have brought up before) has never liked having an open tag without
a closing tag.&nbsp; so, the &lt;br /&gt; format is appealing to me
in that sense.&nbsp; I love that XHTML elements should always be
lower case.&nbsp; I hate upper case HTML.&nbsp; It just reads
funny.&nbsp; Like <a href=
"http://en.wikipedia.org/wiki/CamelCase">camel case function
names</a>.&nbsp; Some folks on our content team used to use Adobe
PageMaker to write up deals.&nbsp; They would copy and paste the
HTML from there into our CMS.&nbsp; The output would be pretty
ugly.<br>
<br>
So, I like parts of both.&nbsp; What is interesting to me is the
fact that the "big sites" on the internet don't seem concerned with
document types or validation.<br>
<br>

<table border="0" cellpadding="5" cellspacing="0">
    <tbody>
        <tr>
            <th align="left" width="33%">
                Site
            </th>
            <th align="left" width="33%">
                DocType
            </th>
            <th align="left" width="33%">
                Validates
            </th>
        </tr>

        <tr bgcolor="#EFEFEF">
            <td>
                Google
            </td>
            <td>
                None
            </td>
            <td>
                <a href=
                "http://validator.w3.org/check?uri=http://www.google.com/">
                No</a>
            </td>
        </tr>

        <tr>
            <td>
                Yahoo
            </td>
            <td>
                HTML 4.01 Strict
            </td>
            <td>
                <a href=
                "http://validator.w3.org/check?uri=http://www.yahoo.com/">
                No</a>
            </td>
        </tr>

        <tr bgcolor="#EFEFEF">
            <td>
                Live.com (Microsoft)
            </td>
            <td>
                XHTML 1.0 Transitional
            </td>
            <td>
                <a href=
                "http://validator.w3.org/check?uri=http://www.live.com/">
                No</a>
            </td>
        </tr>

        <tr>
            <td>
                MSN.com
            </td>
            <td>
                XHTML 1.0 Strict
            </td>
            <td>
                <a href=
                "http://validator.w3.org/check?uri=http://www.msn.com/">
                Yes</a>
            </td>
        </tr>

        <tr bgcolor="#EFEFEF">
            <td>
                Facebook
            </td>
            <td>
                XHTML 1.0 Strict
            </td>
            <td>
                <a href=
                "http://validator.w3.org/check?uri=http://www.facebook.com/">
                No</a>
            </td>
        </tr>

        <tr>
            <td>
                eBay
            </td>
            <td>
                HTML 4.01 Transitional
            </td>
            <td>
                <a href=
                "http://validator.w3.org/check?uri=http://www.ebay.com/">
                No</a>
            </td>
        </tr>

        <tr bgcolor="#EFEFEF">
            <td>
                YouTube
            </td>
            <td>
                HTML 4.01 Transitional
            </td>
            <td>
                <a href=
                "http://validator.w3.org/check?uri=http://www.youtube.com/">
                No</a>
            </td>
        </tr>

        <tr>
            <td>
                Amazon.com
            </td>
            <td>
                None
            </td>
            <td>
                <a href=
                "http://validator.w3.org/check?uri=http://www.amazon.com/">
                No</a>
            </td>
        </tr>

        <tr bgcolor="#EFEFEF">
            <td>
                Wikipedia
            </td>
            <td>
                XHTML 1.0 Strict
            </td>
            <td>
                <a href=
                "http://validator.w3.org/check?uri=http://wikipedia.org/">
                Yes</a>
            </td>
        </tr>

        <tr>
            <td>
                MySpace
            </td>
            <td>
                XHTML 1.0 Transitional
            </td>
            <td>
                <a href=
                "http://validator.w3.org/check?uri=http://www.myspace.com/">
                No</a>
            </td>
        </tr>
    </tbody>
</table>
<br>
So, of the 10 most popular sites on the internet (according to
<a href="http://lists.compete.com/">Compete.com</a>), two don't
include a document type in their front page at all.&nbsp; Only two
of the sites validate according to the W3C.&nbsp; MSN and Wikipedia
both validated on their front page with XHTML 1.0 Strict.&nbsp;
However, neither is sending a Content-Type of
application/xhtml+xml.&nbsp; According to <a href=
"http://hixie.ch/advocacy/xhtml">this page</a>, that is a bad
thing.&nbsp; And the <a href=
"http://validator.w3.org/check?uri=http://search.msn.com/results.aspx?q=xhtml&amp;FORM=MSNH11">
search results page for XHTML on MSN.com</a> did not
validate.&nbsp; Kudos to Wikipedia.&nbsp; Their <a href=
"http://validator.w3.org/check?uri=http://en.wikipedia.org/wiki/Xhtml">
page on XHTML</a> does validate.&nbsp; Interestingly, they switch
to XHTML 1.0 Transitional for that page.<br>
<br>
So, is the internet broken?&nbsp; No.&nbsp; The most important
validation is that of your users.&nbsp; Can they use the
site?&nbsp; Does the site look right in their browser?&nbsp; Most
sites have much bigger navigation and content issues than they do
document structure.<br>
<br>
So, my idea of validation is this:&nbsp;&nbsp; Does it render the
same (or damn near) in the browsers that cover 90% of the internet
users?&nbsp; If so, then your page validates.&nbsp; The only way to
check that is (most likely without SkyNet) the human eye.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Tue, 10 Mar 2009 17:08:29 -0500</pubDate>
            <category>html</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/php-history-newline-closing-tag</guid>
            <title>The history of PHP eating newlines after the closing tag</title>
            <link>http://brian.moonspot.net/php-history-newline-closing-tag</link>
            <description><![CDATA[Have you ever noticed that PHP eats the newlines after a closing
PHP tag?&nbsp; Not sure what I mean?&nbsp; There is lots on
<a href="http://www.google.com/search?q=php+newline+close+tag">Google
about it</a>.&nbsp; Here is an example.<br>
<br>
<code>Hello there!<br>
&lt;?php<br>
<br>
// this is just a dump PHP block<br>
<br>
?&gt;<br>
How are you?</code><br>
becomes:<br>
<br>
<code>Hello there!<br>
How are you?</code><br>
I was talking about this with a coworker tonight.&nbsp; He is
trying to generate some XML and, like me and <a href=
"http://shiflett.org/blog/2005/oct/php-stripping-newlines">Chis
Shiflett</a>, is anal about his output.&nbsp; You see, what happens
in modern use of PHP as a template language is something like
this:<br>
<br>
<code>&lt;?php<br>
<br>
$subelement = range(1, 10);<br>
<br>
?&gt;<br>
&lt;somexml&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;element&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;?php
foreach($subelement as $e) { ?&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;subelement&gt;&lt;?php echo $e; ?&gt;&lt;/subelement&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;?php } ?&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/element&gt;<br>
&lt;/somexml&gt;</code><br>
That code will output this mess:<br>
<br>
<code>&lt;somexml&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;element&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;subelement&gt;1&lt;/subelement&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;subelement&gt;2&lt;/subelement&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;subelement&gt;3&lt;/subelement&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;subelement&gt;4&lt;/subelement&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;subelement&gt;5&lt;/subelement&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;subelement&gt;6&lt;/subelement&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;subelement&gt;7&lt;/subelement&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;subelement&gt;8&lt;/subelement&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;subelement&gt;9&lt;/subelement&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;subelement&gt;10&lt;/subelement&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/element&gt;<br>
&lt;/somexml&gt;</code><br>
So, why does PHP do this?&nbsp; Well, you have to <a href=
"http://marc.info/?t=90279165800002&amp;r=1&amp;w=2">go back 11
years</a>.&nbsp; PHP 3 was emerging.&nbsp; I was just starting to
use it for <a href="http://www.phorum.org/">Phorum</a> at the
time.&nbsp; There were two reasons.<br>
<br>
The first was that you would want the newline after the first
closing tag to be removed as it would remove the existence of the
PHP block completely.&nbsp; At the time, people were shunned for
writing PHP as a tag looking language.&nbsp; <a href=
"http://en.wikipedia.org/wiki/ColdFusion">ColdFusion</a> was new
then too and the PHP community liked to point and laugh at it.<br>
<br>
The second case (and this is probably a more legitimate one) was
that many editors (some still do this for some insane reason) force
every friggin file to end in a newline.&nbsp; We did not have
output buffering in those days.&nbsp; It was the stone age
man.&nbsp; So, to get around the "Headers already sent" errors,
Zeev decided to make the PHP ending tag be "?&gt; with an optional
newline".&nbsp; It was a heated debate on the PHP Internals (then
php-dev) list.&nbsp; So much that I remembered it and <a href=
"http://marc.info/?t=90279165800002&amp;r=1&amp;w=2">dug it up on
MARC</a>.<br>
<br>
Heck, now I want to add to it.&nbsp; I would like it please if PHP
could remove any leading, non-newline whitespace before an open
tag.&nbsp; That would solve this problem.&nbsp; Yeah, more
magic!&nbsp; Nothing like it.<br>
<br>
To me, the worst alternative to all this is the lack of a closing
tag in a file.&nbsp; <a href="http://xkcd.com/100/">My OCD</a> just
can't deal with that.&nbsp; Please, baby seals cry when you don't
use a closing tag.]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Tue, 03 Mar 2009 21:51:18 -0600</pubDate>
            <category>php</category>
        </item>
        <item>
            <guid>http://brian.moonspot.net/wordcraft-0-8-available</guid>
            <title>Wordcraft 0.8 available</title>
            <link>http://brian.moonspot.net/wordcraft-0-8-available</link>
            <description><![CDATA[I am pleased to announce the release of <span><a href=
"http://wordcraft.googlecode.com/files/wordcraft-0.8.tar.gz">Wordcraft
0.8</a>.&nbsp; I have managed to release about once a month since
November.&nbsp; I also have actually gotten some feedback and
tickets posted.&nbsp; Thanks to those that have tried it out.<br>
<br>
I have decided to go back to YUI's Editor.&nbsp; I tried TinyMCE in
the last release.&nbsp; But, using it full time I found it messed
with my HTML too much for my liking.&nbsp; When I would switch to
raw HTML mode and add something like a &lt;code&gt; tag, it would
be lost when saving the data back into the WYSIWYG editor.<br>
<br>
I also converted the admin HTML to HTML 4.01 Transitional.&nbsp; I
never use XHTML anymore these days.&nbsp; So, I was writing invalid
XHTML inadvertantly.<br>
<br>
I worked on the session handling some more in this release.&nbsp;
Users should stay logged in to the admin better now.<br>
<br>
I put comment blocks in all the files and documented every
function.&nbsp; This should help anyone wanting to dig in and help
out.<br>
<br>
I fixed several bugs reported by users (or maybe just testers, not
sure).&nbsp; Thanks for that and keep the feedback
coming.<br></span>]]></description>
            <dc:creator>brianlmoon</dc:creator>
            <pubDate>Mon, 23 Feb 2009 08:00:00 -0600</pubDate>
            <category>Blogging</category>
            <category>MySQL</category>
            <category>PHP</category>
        </item>
    </channel>
</rss>
