Archive for the ‘ Tutorials ’ Category

Tutorial: Using TextWrangler to Edit Your Protected System Files

Friday, November 9th, 2007

Tips and Tricks

If you are a web developer, you undoubtedly have needed to edit a system config file from time to time. Your choices in the terminal are nano, and …well, nano. If you happen to have BBEdit installed, then you can use that as well. However, BBEdit costs $125, which is pretty steep if you just need a text editor.

Yee-ha! (sorry. I couldn’t help myself. I am from Texas, y’all). Turns out that BBEdit has a little brother called TextWrangler that has the advantage of being both free and powerful. Me rikey things that are free.

First, download TextWrangler from the Bare Bones Software site.

Next, when you install it, be sure to say ‘yes’ when asked if you want to install the command line tools. This integrates TextWrangler with the Terminal so that you can launch from the command line. Let’s say you want to edit your hosts file. You’d simply type:

sudo edit /etc/hosts

It’s that simple.

Now, let’s Automate this for frequently edited docs such as your Apache config or hosts files. Launch Automator and create a new, Custom workflow.

Add a Run AppleScript action. Enter the following:

do shell script "sudo edit /etc/hosts" password "[YOUR ROOT PASSWORD]" with administrator privileges

Automator Action Screen Shot

Save the workflow as an application. Now, you can edit these protected system documents with ease.

Tip: Use QuickSilver to launch your Automator script with a few keystrokes.

Enjoy.

 

Setting up a Web Server on Leopard (OS X 10.5) and Snow Leopard (10.6) Using MAMP – A Step by Step Guide (Revised)

Wednesday, November 7th, 2007

MAMP Web Server

Recently, I wrote a Step-by-Step guide for installing a basic development server on Mac OS X Leopard (10.5) using the built-in packages. It turns out that the version of PHP that is packaged with Leopard is missing many commonly used components such as the GD Library, MCrypt, and many others. Since recompiling PHP on Leopard is no small feat even for experienced developers, you may be looking for an alternative method to get your web server working.

UPDATE: Based on preliminary testing, these instructions remain up to date for Snow Leopard (10.6).

This is where MAMP comes in handy. This tutorial will walk you through the steps necessary to get MAMP set up on your site, migrate your existing data, and set up multiple virtual hosts.

Revision Notes 02/03/08: Several readers have kindly pointed out some errors in the guide that follows. I’ve updated this article to correct some (all?) of these mistakes/omissions.

MAMP

MAMP (Macintosh, Apache, MySQL, PHP) is a tool released by a German company called living-e. MAMP comes in two flavors: free and Pro. The pro version is not free (appx. $70 at the time of this writing), but offers a bunch of convenient power tools to help you configure virtual hosts, your Apache server, and your startup items.

However, with a few simple tweaks to the httpd.conf, php.ini, and hosts file, the free version of MAMP should be more than adequate for most developers.

Overview

This tutorial can be used whether you are installing a web server for the first time or are migrating from Tiger (10.4), or have set up a default installation on Leopard. Steps aimed at migrating your data and settings are labeled with an "optional" tag.

Step 1: Enable your root password

  1. Open the Directory Utility: In the Finder, navigate to the Utilities folder (tip: click on the desktop, hit Cmd+Shift+U).
  2. Click on the padlock to allow edits.
  3. Go Edit > Enable Root Password
  4. Enter and re-enter your password.

Now, you are set to access protected areas of the system via the terminal.

Step 2: Export your existing data (optional)

If you were running a web server previously, you’ll want to transfer your data and settings. The best way to get your MySQL data is to use the MySQL Administrator tool to backup all of your databases.

  1. Download and install the MySQL GUI Tools. You’ll only need the Administrator tool, but the others are good to have as well.
  2. After installing the package, open MySQL Administrator.
  3. Connect to your existing database(s).
  4. Click the "Backup" tab and run a backup routine to save your database as sql dump file on your local drive.

Alternatively, you can use phpMyAdmin to export your data if your database is under 2mb (typically). I found this method to be unusable for large databases, however.

You can also use the mysql dump command line tool. This effectively creates the same dump file as the Administrator Tool, but is not nearly as easy and foolproof to use.

Regardless of the method you choose, you should have one or more sql files ready to be imported.

Why not just copy the data files? After many, many attempts to do this, I was unable to end up with a running database, even after trying to preserve permissions.

Step 3: Save your existing settings (optional)

If you have previously set up your own server, you are likely to have settings you want to preserve. You’ll need backup copies (or access to) the following files:

  • httpd.conf
  • httpd-vhosts.conf (Apache 2)
  • httpd-userdir.conf (Apache 2)
  • php.ini
  • hosts (Leopard, Windows, or *nix; Tiger & previous OS Xes used Net Info and don’t use a hosts file)

Step 4: Shut down built-in servers

If you have installed and configured Web Sharing and a MySQL database on your machine, we’ll need to ensure these are shut down before proceeding. If you have not, then skip to the next step.

  1. In your System Preferences > Sharing control panel, uncheck Web Sharing
  2. If you have MySQL installed, in a terminal window, type the following to shut down the existing MySQL server:

    sudo /usr/local/mysql/support-files/mysql.server stop

  3. In a terminal window, type the following to remove any previous MySQL start-up items:

    sudo rm -R /Library/StartupItems/MySQLCOM

Step 5: Download and install MAMP

  1. Go to the MAMP web site and download the MAMP package.
  2. Extract and mount the dmg package. Drag MAMP (not MAMP Pro) to your Applications folder.
  3. Go to /Applications/MAMP and launch the MAMP Control Panel.
  4. Start the servers by clicking the "Start Servers" button.
  5. Do not change any of the settings at this time. Just run defaults for the moment.

Step 6: Test your installation

Click on the "Open Start Page" button. This should launch the MAMP start page.

Congratulations. You have a perfectly fine web server running on your machine. This may be fine for some people‚ in which case, you’re done‚ but web developers are going to need to tweak a few settings.

You’ll notice from your URLs that you are running on an unusual port number (8888). This is fine for the time being, but you’ll probably want to switch to the default ports to avoid having to tack on ":8888" to every local domain.

To make changes, let’s shut down the server by clicking the "Stop Servers" button.

Step 7: Switch to HTML & MySQL default ports (optional)

  1. With the MAMP Control Panel still open, click the "Preferences…" button.
  2. Click the "Ports" tab
  3. Click the "Set to default Apache and MySQL ports" button to change the Apache port to "80" and the MySQL port to "3306".
  4. Click Ok.

Step 8: Transfer your existing settings (optional)

MAMP keeps its config files in the Applications/MAMP/conf/ directory.

There are a million ways to get your settings over from your old server, including simply tweaking the settings by hand. I find the safest way to do this is to use a file comparison tool like the FileMerge tool included with XCode (included on your Leopard disc) to transfer settings surgically from your old server to your new one.

Regardless, this is the time to move your settings over if you want to customize your installation. Be careful here. This is the most common way to screw things up.

Step 9: Import your existing data (optional)

If you exported your data in Step 2, you’ll want to import them to your new MySQL server. The best way to get your MySQL data is, again, to use the MySQL Administrator tool to backup all of your databases.

  1. Connect to your existing database(s).
  2. Click the "Restore" tab. Select the file(s) saved in Step 2 to reconstruct your database(s).

Alternatively, you can use phpMyAdmin’s import tool.

Step 10: Install PEAR (optional)

PEAR is a companion to PHP that is typically installed by default along with PHP. PEAR is a set of applications, modules and pre-packaged classes that provide a wealth of functionality to your apps with minimal effort. One example covered on this blog is how to implement an elegant caching mechanism with just a few lines of code. Using PEAR is highly recommended.

If you do not already have PEAR installed, type the following in a terminal window:

curl http://pear.php.net/go-pear > go-pear.php
sudo php -q go-pear.php

This will auto-install and pre-configure PEAR for you. Accepting the defaults during the installation should be fine for most users.

Now, we need to tell MAMP’s version of PHP to look for the PEAR files. To do this, we’ll need to modify the php.ini config file installed by MAMP. First, back up the config file by typing the following in a terminal window:

sudo cd /Applications/MAMP/conf/php5/
sudo cp -p php.ini php.ini.bak

Now, edit the php.ini file, open "/Applications/MAMP/conf/php5/php.ini" in your favorite text editor.

Scroll down to the include_path directive and change the following [↵ shows line wraps -Ed.]:

FROM:

include_path = ".:/Applications/MAMP/bin/php5/lib/php"

TO:

include_path = ↵
".:/Applications/MAMP/bin/php5/lib/php:/usr/share/pear"

Step 11: Set up your first virtual host (optional)

Virtual hosts are Apache’s way of letting you serve up multiple sites on a single server. Name-based virtual hosting is a convenient way to do this. Not everyone needs to set up a virtual host. For instance, if you are just tinkering on a single site, then you can skip this step. However, if you are developing and testing multiple sites locally, you will need to do this step.
For this example, we’re going to set up a test site called "site1". With a name-based virtual host, all we’d type in is "http://site1/".

In order to make this work, we’ll need to edit the hosts file on your machine. (Note: In Tiger and previous versions of OS X, you accomplished this through the NetInfo dialog. Since the NetInfo dialog was killed in Leopard, we do this the same way you do this for *nix and Windows by editing the hosts file directly).

To edit your hosts file, type in the terminal:

sudo nano /etc/hosts

Below the default entries, you’ll add the following:

# My sites
127.0.0.1 site1

The following is a screenshot of my hosts file. Yours will be similar but different:

Screenshot of my hosts file

Save your changes.

Now, we’ll need to add a corresponding virtual host. But first, Apache wants us to add our existing default directory as the very first virtual host. This is critical, so do not skip this step.

To edit your virtual hosts file, open "/Applications/MAMP/conf/apache/httpd.conf in a text editor.

Uncomment the virtual host directive:

NameVirtualHost *

Replace the two example virtual hosts with the following:

<VirtualHost *>
DocumentRoot &quot;/Applications/MAMP/Library&quot;
ServerName localhost
</VirtualHost>

Next, add your first virtual host similar to the following:

<VirtualHost *>
ServerName site1
DocumentRoot /path/to/site1
</VirtualHost>

This is a screenshot of the vhosts section of my http.conf file. Yours will be similar but different:

Screenshot of vhosts file

Who do we have to add our default directory first? According to the Apache Docs on Virtual Hosts, they recommend the following:

If you are adding virtual hosts to an existing web server, you must also create a <VirtualHost> block for the existing host. The ServerName and DocumentRoot included in this virtual host should be the same as the global ServerName and DocumentRoot. List this virtual host first in the configuration file so that it will act as the default host.

Note: Failing to add my default directory as the very first virtual host tripped me up for days. If your virtual hosts are defaulting to an unexpected directory, this is likely to be the culprit.

Step 12: Restart the servers

Back in the MAMP Control Panel, click the &quot;Start Servers&quot; button to restart Apache and MySQL with your new settings. Fingers crossed, everything went well, and you can now access your local test sites.

If something went wrong, retrace your steps. The most likely cause is a mis-configuration in your Apache config file. To check the syntax of your conf file, type the following into a terminal window:

cd /Applications/MAMP/bin/apache2/bin
sudo ./apachectl -t

Repair your config file as necessary.

Step 13: …

There is no step 13. I just didn’t want to end on a bad number.

Step 14: Create a startup item

Now that you have everything running, you’ll probably want to launch the web server on start up. One of the nice things about MAMP Pro is its built in ability to start itself up on login. The free version of MAMP does not have this luxury, but this is easily solved by creating a launch daemon.

Follow this tutorial to get MAMP to launch silently on startup.

Conclusion

By this point, you should have a fully functional development server that you can extend and expand as you take on new projects.

Please feel free to add comments below if you find errors or problems with the guide above.

Good luck.

Setting up a Web Server on Leopard (OS X 10.5) or Snow Leopard (10.6) Running PHP, Apache, and MySQL – A Step by Step Guide

Monday, November 5th, 2007

Tips and TricksOne of the great advantages of developing web sites on a Mac is the fact that all of the tools you need to run a web server are pre-installed. Getting them to work and play well together requires a little work—especially in Leopard.

If you are simply wanting a web server to host your personal web site, then you might want to consider stand-alone, point and click apps like XAMPP and MAMP. These turnkey solutions set everything up for you and are great solutions if you are just starting or have simple needs.

However, if you want to set up a development environment running multiple test sites using the free tools already installed on your Mac, and you aren’t afraid of the terminal, then read on.

UPDATE: Based on preliminary testing, these instructions remain up to date for Snow Leopard (10.6).

UPDATE: Since posting this tutorial, I have learned that the stock installation of PHP does not include several critical libraries. After several days of experimenting, I finally landed on MAMP as my production solution. I have published a walk-through for setting MAMP up on your machine [link].

NOTE: This guide is specific to getting a server running on Leopard 10.5. Earlier versions of the OS are not covered here.

This guide will walk you through the steps needed to get a development environment set up and running on your copy of Leopard. In this, we will do the following (click on each to jump to the corresponding section):

  1. Enable your root password
  2. Install the Xcode Tools
  3. Edit your Apache configuration file
  4. Set up your first virtual host
  5. Start/Restart Apache
  6. Test Apache
  7. Test PHP
  8. Load MySQL
  9. Install phpMyAdmin
  10. Install PEAR

Overview

A commonly used web server solution consists of 3 major components: Apache web server, a MySQL database, and the PHP scripting engine. This is the "AMP" in LAMP. (The "L" is "Linux"). This set up is widely used in the development community for two reasons: 1) it’s free and open source, 2) it’s very mature. "AMP" components are included in every copy of OS X, but getting them to work requires a few steps.

Step 1: Enable your root password

  1. Open the Directory Utility: In the Finder, navigate to the Utilities folder (tip: click on the desktop, hit Cmd+Shift+U).
  2. Click on the padlock to allow edits.
  3. Go Edit > Enable Root Password
  4. Enter and re-enter your password.

Now, you are set to access protected areas of the system via the terminal.

Step 2: Install the Xcode Tools

While this isn’t strictly necessary, it’s good practice for developers to install the Xcode tools provided for free on your Leopard disc. You’ll need it at some point, so go on and install it.

  1. Insert your Leopard DVD
  2. Navigate to Optional Installs > Xcode Tools > XcodeTools.mpkg
  3. Run the installer.
  4. Go get a cup of coffee.

Step 3: Edit your Apache configuration file

Note: throughout this guide, you will need to edit configuration files. There are several ways to do this. My preferred method is to use an app called BBEdit that allows you to edit protected files more gracefully than, say, TextEdit or the terminal window. However, BBEdit is not free. For the purposes of this tutorial, I’m going to stick with the terminal method that uses the editor called "nano" just because it’s included on every system.

In the terminal, type:

sudo nano /private/etc/apache2/httpd.conf

Note: "sudo" is a command that lets you perform a specific task with root privileges without having to log in as the root. This is the recommended method of mucking about in the terminal as it is safer than being logged in as root.

  1. Scroll down to about line #114. You’ll see the following:
    #LoadModule php5_module      libexec/apache2/libphp5.so

  2. Remove the hash mark as follows:
    LoadModule php5_module       libexec/apache2/libphp5.so

  3. In order to run multiple sites on this server, you will want to use virtual hosts. Scroll down to the bottom of the document (about line #461) and remove the hash from the Virtual Hosts entry as follows:
    Include /private/etc/apache2/extra/httpd-vhosts.conf

  4. Exit and save httpd.conf.

Step 4: Set up your first virtual host

Virtual hosts are Apache’s way of letting you serve up multiple sites on a single server. Name-based virtual hosting is a convenient way to do this.

For this example, we’re going to set up a test site called "site1". With a name-based virtual host, all we’d type in is "http://site1/ ".

In order to make this work, we’ll need to edit the hosts file on your machine. (Note: In Tiger and previous versions of OS X, you accomplished this through the NetInfo dialog. Since the NetInfo dialog was killed in Leopard, we do this the same way you do this for *nix and Windows by editing the hosts file directly).

To edit your hosts file, type in the terminal:

sudo nano /etc/hosts

Below the default entries, you’ll add the following:

# My sites
127.0.0.1 site1

Save your changes.

Now, we’ll need to add a corresponding virtual host. But first, Apache wants us to add our existing default directory as the very first virtual host. This is critical, so do not skip this step.

To edit your virtual hosts file, type in the terminal:

sudo nano /etc/apache2/extra/httpd-vhosts.conf

Replace the two example virtual hosts with the following:

<VirtualHost *>
  DocumentRoot "/Library/WebServer/Documents"
  ServerName localhost
</VirtualHost>

Next, add your first virtual host similar to the following:

<VirtualHost *>
  ServerName site1
  DocumentRoot /path/to/site1
</VirtualHost>

Who do we have to add our default directory first? According to the Apache Docs on Virtual Hosts, they recommend the following:

If you are adding virtual hosts to an existing web server, you must also create a <VirtualHost> block for the existing host. The ServerName and DocumentRoot included in this virtual host should be the same as the global ServerName and DocumentRoot. List this virtual host first in the configuration file so that it will act as the default host.

Note: Failing to add my default directory as the very first virtual host tripped me up for days. If your virtual hosts are defaulting to an unexpected directory, this is likely to be the culprit.

Step 5: Start/Restart Apache

  1. If you haven’t done so already, go Apple Menu > System Preferences > Sharing
  2. Ensure that “Web Sharing” is checked

Tip: To restart Apache in the future, you can come to the same control panel, uncheck and recheck the Web Sharing item.

Tip: Alternatively, you can type the following into a terminal:

sudo /usr/sbin/apachectl graceful

Tip: Alternatively, you can create an Automator script as follows:

  1. Open a new, blank, custom workflow
  2. Add a “Run AppleScript” action.
  3. Type the following, replacing values as necessary:
    do shell script "sudo /usr/sbin/apachectl graceful" password "[YOUR ROOT PASSWORD]" with administrator privileges
  4. Save the workflow as an Action.

Step 6: Test Apache

In a browser, load your localhost: http://localhost

If you see the default Apache home page (which contains a red and blue feather image), your Apache server is set up correctly. If you do not, then you might try checking your Apache config syntax:

sudo apachectl -t

Step 7: Test PHP

In your favorite code editor, create a new php file and call it "info.php". In this file, enter the following code:

<?php phpinfo(); ?>

Save the file to the root of your local host directory (e.g. "/Library/WebServer/Documents/info.php") directory. In your browser, navigate to the file (e.g. "http://localhost/info.php").

You should see a purple and white table containing all the PHP variables, modules, and settings. If you don’t see this table, backtrack to Step 3 above to ensure you’ve enabled PHP in your Apache config file correctly.

Step 8: Load MySQL

  1. Download and unzip the MySQL Package for Mac OS X.
  2. Install the main MySQL installer.
  3. Install the Start Up Script.

As of this writing, MySQL has not been updated to support Leopard. You will be downloading the package for Tiger (10.4) and making the following modifications:

  1. Do NOT install the MySQL control panel. As of this writing, it does not work with Leopard.
  2. Start MySQL manually by typing the following into a terminal:
    sudo /usr/local/mysql/support-files/mysql.server start

MySQL should now be running silently in the background.

A new issue with Leopard’s installation of PHP is that it expects MySQL to be somewhere other than where it is installed by the package. To fix this, we need to create a new MySQL configuration file. To do this, create a text file and save it as "/etc/my.cnf". Enter the following text:

[client]
socket = /var/mysql/mysql.sock

[mysqld]
socket = /var/mysql/mysql.sock

In a terminal window, type the following in order to create a folder where the MySQL sock file will live:

sudo mkdir /var/mysql
sudo chown _mysql /var/mysql

Note: If you are using any of the MySQL Tools (e.g. MySQL Administrator, etc.), you’ll need to tell them where to find the sock file. To do this, click the Advanced drop-down on the connection dialog, and enter “/var/mysql/mysql.sock“.

At this point, you should have a fully functioning database. Now, let’s get some data in there.

Step 9: Install phpMyAdmin

phpMyAdmin (PMA) is a popular and free tool to manage your MySQL databases. It is an integral part of most LAMP development environments.

  1. Download and unzip the latest stable release of phpMyAdmin.
  2. Copy the files to a directory of your choice. For this example, we’ll install it in "~/Sites/phpmyadmin/".
  3. Per Step #4 above, add this directory as a virtual host called "pma".
  4. Restart Apache to initialize your new virtual host.
  5. Follow the installation instructions provided in the PMA download to set up the config file.
  6. If you can navigate to PMA (e.g. "http://pma", you’ve good to go.

Step 10: Install PEAR

PEAR is a companion to PHP that is typically installed by default along with PHP. PEAR is a set of applications, modules and pre-packaged classes that provide a wealth of functionality to your apps with minimal effort. One example covered on this blog is how to implement an elegant caching mechanism with just a few lines of code. Using PEAR is highly recommended.

In a terminal window, type the following:

curl http://pear.php.net/go-pear > go-pear.php
sudo php -q go-pear.php

This will auto-install and pre-configure PEAR for you.

Now, we need to tell PHP to look for the PEAR files. To do this, we’ll need to modify the php.ini config file. First, copy the default config file and rename it php.ini by typing the following in a terminal window:

sudo cp /etc/php.ini.default /etc/php.ini

Now, edit the php.ini file:

sudo nano /etc/php.ini

Scroll down to line #469 or so and edit the include_path variable by removing the comment hash and adding the PEAR path as follows:

include_path = ".:/php/includes:/usr/lib/php:/usr/share/pear"

Restart Apache and ensure everything loads and runs as expected.

Conclusion

By this point, you should have a fully functional development server that you can extend and expand as you take on new projects.

Please feel free to add comments below if you find errors or problems with the guide above.

Good luck.

Tip: Decrease Load Times with CSS Sprites

Friday, October 19th, 2007

CSS SpritesBack in the day, I produced video games for a living, so when I heard that sprites were a great way to improve site performance, I had to put my way-back hat on.

A sprite, if you don’t know, is a single graphic file that contains many elements used to display, say, tiles in your favorite side-scroller (Metal Slug, anyone?), or, in this day and age, background elements on a web site. Instead of displaying the entire file, only a portion of the graphic file is revealed. Fortunately, this is a simple thing to do with CSS’s background property.

The performance gains on a web site are achieved by grouping elements together to reduce the number of http requests made to the server. For each graphic element, JavaScript file, and CSS file on your web page, your browser makes a separate http request to the server, complete with browser info and a bunch of overhead crap that you don’t need. Combining, reusing, and reducing are the three keys to performance.

Excellent candidates for CSS Sprite optimization are gradient backgrounds, rollover-buttons, tab elements, or rounded graphic box elements. Creating a sprite is easy, but tedious. You’ll want to do this only once the design is locked, since going back and making changes can be a pain.

For the purposes of this article, let’s look at a recent example of how CSS sprites reduced page load times dramatically. TheFreelanceNation.com is a client site I did recently where the design was handed to me. The site consists of many rounded “gel” elements, each of which required 9 graphic elements.

CSS Sprites

CSS SpritesBy grouping all of the page elements into two files–one for the rounded corners, and another for horizontally repeating elements–the number of overall http requests dropped by almost 70% (120+ down to 35 or so). I was able to reduce this further by grouping and compacting JS files and CSS files, but that’s a topic for another day.

In Photoshop, open the elements you want to group together. Then add each to a master file, making sure to draw guides on the boundaries so you can easily measure the pixel locations later. The rule of thumb is to group elements that repeat together. Meaning if you have elements that repeat-x, you’ll group them in a tall file. Elements that repeat-y will go together in a wide file. Save this in an optimal file format (I find that 8-bit, PNG, difussion dithered is best for all but the most colorful sprite files, in which case 24-bit will do). Experiment in Photoshop’s Save for the Web dialog to get the best result.

Once you have your grouped file ready, adapt your CSS files as follows:

.orangeBG {
background:url('/images/sprites.png') repeat-x 0 0;
height:20px;
}
.greenBG {
background:url('/images/sprites.png') repeat-x 0 -20px;
height:20px;
}
.blueBG {
background:url('/images/sprites.png') repeat-x 0 -40px;
height:40px;
}

…etc.

Notice two things:

1) is the use of shorthand. The background shorthand syntax is “background:[url] [repeat] [xpos] [ypos]. While this isn’t strictly necessary, it makes things a lot cleaner.

2) the starting point of CSS element within the sprite is measured in negative pixels. (It took me a while to figure this one out.)

Play around with this. The technique is surprisingly simple once you get the hang of it, and the results can be stunning. You’ll find initial page loads to be faster, and subsequent cached reloads to be much snappier.

Tutorial: Filtering Bad Email Domains Like “DodgeIt.com”

Wednesday, March 21st, 2007

If you need a valid and active email address as part of your registration process, you may have come across services like “DodgeIt.com” that allow users to create temporary addresses for the sole purposes of completing the email validation process.

For example, let’s say you have an e-commerce site and in order to send receipts, you need to ensure that the user has provided a legitimate email account. During registration, you accept the user’s information and send a confirmation e-mail containing a validation link that completes the registration process. Someone who wishes to remain anonymous for whatever reason could use a service like DodgeIt and spoof your validator.

Blocking these domains is a relatively simple matter. Simply add the following function to your validation pass and flag matching domains as an address that you do not accept.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function filterBadEmailDomains($email) {

// Filters against a list of "bad" domains.
// Returns FALSE if the domain is bad; TRUE if it's good
// Add additional banned domains to the $blockedDomainArr array

$blockedDomainArr = array('dodgeit');
$retVal = true;
$emailParts = explode('@',$email);

foreach($blockedDomainArr as $blockedDomain) {

if(strstr($emailParts[1],$blockedDomain)) {
$retVal = false;
}

}

return $retVal;

}

This example singles out DodgeIt, but as other similar services come on line, you can add their domains to the $blockedDomainArr array and include them in your validation.

Enjoy.

Tutorial: Validating E-Mail Addresses, Including GMail “Plus” Addresses

Wednesday, March 21st, 2007

I’ve been asked often enough that it is worth a quick tutorial to demonstrate how to validate email addresses–or, at least, validate if an email address looks valid–that include two tricky, but valid, formats.

In addition to normal addresses, we started getting false negatives on otherwise legitimate emails that contained periods in the name as well as plus (“+”) symbols. Examples include:

[email protected]

[email protected]

The latter is a very helpful trick with the GMail system that allows you to use a single address (“realname”) and tack on a tag that can be filtered or simply used in development to provide a unique address without the need to open up multiple test mail accounts (e.g. [email protected]).

In both cases, these can be legitimate addresses, so we had to modify our pattern validator. We use the following function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function validateEmailPattern($email) {

// Filters against a pattern that conforms to a valid email address pattern
// Returns FALSE if the email address is bad; TRUE if it's good

$retVal = false;
$pattern = '#^([._a-z0-9-+]+[._a-z0-9-+]*)@(([a-z0-9-_]+)(.[a-z0-9-_]+)?(.[a-z]{2,6}))$#i';

if(preg_match($pattern, $email)) {
$retVal = true;
}

return $retVal;

}

This will return TRUE if the pattern appears to be valid, false if not.

Enjoy.

Tutorial: Working Around IE6’s Caching of AJAX Content

Saturday, March 17th, 2007

Microsoft, in their infinite wisdom, decided that it would be most efficient to cache any content returned by “ActiveXObject(“Microsoft.XMLHTTP”)”, the driver behind the now ubiquitous AJAX functionality.

The symptom you’ll see is that the results displayed when requesting AJAX content is actually stale and no amount of refreshing–even of the page itself–will force new content to appear. The old “pragma no-cache” solution that forces IE6 to get the refreshed page’s content from the server does not apply here.

The real-world example I’ll give is of the Live Scoring scoreboards we use on McKinneyNews.net. Here, we display a graphical scoreboard and accompanying text updates that follow a game in real-time. To avoid a mini-DDOS attack by having everyone constantly refreshing the page every few seconds (a story for another day), we implemented these scoreboards as AJAX elements that update every 30 seconds. As this feature started getting more popular, we started hearing from more and more users that the scoreboards were simply not updating when indicated, and, in fact, often reverted back to an earlier score.

The culprit turned out to be this caching bug feature in IE6. The solution is actually easy to implement.

Let’s say you have a generic AJAX setup as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// JavaScript Document

function createRequestObject() {
  var ro;
  var browser = navigator.appName;
  if(browser == "Microsoft Internet Explorer"){
    ro = new ActiveXObject("Microsoft.XMLHTTP");
  }else{
    ro = new XMLHttpRequest();
  }
  return ro;
}

var http = createRequestObject();

function sndReq(divId, procpage) {
  http.open('get', procpage);
  http.onreadystatechange = handleResponseGen;
  http.send(null);
}

// generic updates
function handleResponseGen() {
  if(http.readyState == 4){
    var response = http.responseText;
    var update = new Array();

    if(response.indexOf('|' != -1)) {
      update = response.split('|');
      document.getElementById(update[0]).innerHTML = update[1];
    }
  }
}

You’ll notice that the sndReq function accepts the procpage variable. This is the path to your PHP AJAX processor page, plus any query parameters. For example:

/inc/ajax_do_something.php?id=3

This is the crux of the problem. In this example, we’re calling the same “id=3″ over and over again. P.O.S.6 IE6 sees this repeated URL and thinks to itself, “Self, I’ll just save my user a lot of time and effort and use the cached version of this content.” IE6, you would be wrong. The assumption that the AJAX content would be the same is asinine. AJAX content by definition is dynamic, so I can’t think of a case in which it should be cached. Regardless, IE6 does this.

The way around it is to beat IE6 at its own game and provide a pseudo-unique URL for the AJAX request. This is easily accomplished by adding a randomly generated number as an additional (and superfluous) URL parameter. Time codes work well and are more or less guaranteed to be unique. However, 99.99% of the time, a simple random number is all that’s needed.

An updated sndReq function and a new, simple pseudo-random number generator is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function sndReq(divId, procpage) {

  // tack on a random number. This provides a psudo-unique
  // key that forces IE to NOT cache the AJAX content.
  procpage=procpage+"&rand="+calcRand();

  http.open('get', procpage);
  http.onreadystatechange = handleResponseGen;
  http.send(null);
}

function calcRand() {

  var retVal = Math.floor(Math.random() * 1001);
  return retVal;

}

With the somewhat unique query parameter, IE6 thinks that it is calling something new and does not revert to its cached version of the content.

Problem fixed.

Recommendation: CakePHP

Monday, March 12th, 2007

CakePHPFor a while now, I’ve been searching for a better framework that facilitates rapid PHP site development. My own bootstrap framework is getting a little long in the tooth, and Ruby on Rails requires too great an investment in unbillable time and effort to switch over. Enter CakePHP. This article discusses what I’ve discovered so far (I’m still in the early days of experimentation) for this promising framework.

DST: Good, but Could be Better

Dynamic Site TemplateAs I mentioned, I’ve built my own site bootstrap framework called DST. DST (Dynamic Site Template) has been very effective for me. On the plus side, it is well integrated with Dreamweaver’s canned PHP and takes care of all of the mundane things you need to code for a dynamic site such as user logins and basic site news publication. However, as with Dreamweaver’s application model, my bootstrapper adheres to the old, top-down style of doing things. I’ve also found that DST is a little hard for third-party contractors to learn quickly, making it difficult at times to get help when I need it.

So I’ve been looking for a solution that is based on a MVC (Model View Controller [wikipedia]) structure and allows skinning. While I will be giving up tight Dreamweaver integration, I feel the benefits of an MVC framework outweigh the inability to build pages in Design View. Frankly, Design View hasn’t worked reliably for me in ages and serves as little more than a way to quickly jump around massive pages, so giving this up is not a huge sacrifice.

Ruby on Rails: Great Framework, New Language

Ruby on RailsOf course, I checked out Ruby on Rails [link]. I loved the structure and the ability to scaffold the site, building it up piece by piece. I’ve even worked on some large scale projects where RoR was used extensively.

The biggest drawback to RoR for me, personally, is the fact that it’s written in Ruby and not PHP. This means I have to learn yet another language, which represents a huge investment in un-billable time and effort. Furthermore, getting RoR to run in a Mac environment is less than trivial. And finally, getting RoR to work within Dreamweaver was a major exercise in hackery. Perhaps CS3 will address these deficincies, but in the mean time, my search continues.

Cake: Best of Both Worlds?

I was recently turned onto a framework called CakePHP [link] which is a sort of “Ruby on Rails for PHP.” I’m a few days into experimentation, but so far the framework looks very promising. Cake does, indeed, boast many of the same benefits as RoR. It uses the same MVC model, and building pages uses the same approach. In other words, if you’re familiar at all with how you build a site in RoR, you’ll be up and running on Cake in no time.

On the negative side, getting Cake to run in my Mac environment was a lesson in hair pulling and anger management. However, to be completely fair, the problem turned out to entirely my fault. Very quickly, the problem was that I didn’t copy over a much needed .htaccess file. I’ve written a companion article [link] that talks about the issue. So just this morning, I started from scratch and it worked like a charm.

I’m looking forward to doing more R&D on Cake. My goal is to develop a bootstrapper on the Cake framework that allows me to build sites for clients much more rapidly, but also provides a stronger foundation for changes and feature additions down the road.

Stay tuned.

News: Adobe Shipping Two Versions of Photoshop CS3

Thursday, March 8th, 2007

AdobeMacWorld reports that Adobe will be shipping two versions of Photoshop CS3, one called “Extended” that is aimed at video professionals and 3d modelers, and the one we are familiar with from the Beta.

Photoshop Extended will contain a superset of features–still to be disclosed–that aid in integrating Photoshop more readily in video production or 3d pipelines. Having worked in the video game industry for years, I can attest that this is sorely needed.

However, for web developers, regular old Photoshop will do just fine, thankyouverymuch.

Retail Economics 101: Vista at Retail

Friday, February 9th, 2007

vista_logo.gifI visited Staples the other day and experienced a practical lesson in price inelasticity. Elasticity is the measure of how sensitive a given economic widget is to pricing. An elastic product can withstand changes in pricing. An inelastic one will see dramatic declines in sales as the price goes up. In this case, the economic widget is an operating system: a retail copy of Vista. I would argue that Microsoft is learning the hard way that Vista is a highly inelastic product. In addition, they’re doing a surprisingly bad job of going that last mile at retail to close the deal.

Staples, like many retailers, has tables and end-caps set up specifically to showcase Vista. Laid out on the table are the various versions available: Premium Upgrade, $159.99; Premium full, $239.99; Business Full, $299; all the way up to Ultimate full at an astounding $399.99. 8 boxes in all, and with multiple copies of each, to boot, making the visual array even more confusing. I have read about these prices for months, but seeing them there at retail and holding the small, empty display box in my hand puts it in context: “You’ve got to be kidding,” I thought. “You want $400 for this???

I was wondering if I was the only one, so as a bit of an experiment, I stood off to the side and watched the Vista display. Person after person came up and performed the same procedure: pick up the box, look at the price, widen eyes in surprise, put the box down, and walk away empty-handed. I counted 10 in a 5-minute period. Not scientific, I admit, but I do have better things to do with my time than get kicked out of Staples for some unauthorized retail research.

This experience hit home some of the lessons learned in my MBA program in a real and literally tangible way:

Lesson #1: Keep it simple, stupid. Refine the product line and don’t offer a seemingly infinite and confusing array of product variations.

Lesson #2: Pay attention to touch-points. The display boxes should not be empty. When you pick up a $400 product in your hand, it should feel substantial, not vacuous.

Lesson #3: Pay attention to price. If my experience is any indication, $400 is simply too much to ask for a new OS, especially when you consider that most purchases of Vista will require at a minimum a new graphics card and some extra memory. You’re asking someone to plunk down $1,000 of hard-earned cash for?¢‚Ǩ¬¶what? A slightly better user experience? Slightly better security? I’ll stick with XP, thankyouverymuch.

In the end, this amounted to nothing more than an interesting mental exercise. I know that Vista will one day become the predominant OS in the world. I know that Microsoft will eventually pry some amount of money from my pocket for Vista; it’s like a black hole in my life as a developer into which I will eventually fall. I also know that Microsoft hardly listen to someone like me. After all, I’m just a customer. However, I wonder if, just maybe, if my experience, replicated at tens of thousands of retail stores around the country, will equate to a slower than expected adoption rate. Time will tell.