Chomper Stomping jQuery/JavaScript/CSS 3/HTML 5, Java/PHP/Python/ActionScript, Git, Chrome/Firefox Extensions, Wordpress/Game/iPhone App Development and other random techie tidbits I've collected

10Jun/098

Creating Dynamically Re-sizable Buttons for iPhone Apps

Creating buttons that resize/stretch themselves automatically for your iPhone Applications is pretty easy.

Buttons are created as .png files with three parts: Left end-cap, middle (the stretch-able part), Right end-cap. Basically, you create a little tiny .png file with the left and right end caps (or top and bottom) and a little bity middle part that the iPhone will automatically re-size to fit any width or height you make the button.

I'll walk you through the process step by step and show you how to assign the image to your button.

If you are wondering how to get your Round Rect Buttons to look like the ones in the official iPhone apps (like the ones apple makes), this tutorial will show you how. Instead of creating your own button image, just use the ones from Apple, or download the zip file for this tutorial (the ones from Apple are in there too)

Creating the Stretchable iPhone App Button Image

To start with, you will need to actually create the button image. I used Fireworks to do this, but you could use Photoshop, Illustrator, Inkscape or Gimp if you are so inclined. I recommend Fireworks.

I wanted my button to mimic normal iPhone buttons, but also illustrate the concept of a "stretchy" button. So I made a square button with rotated square corners.

  1. Create a new image 30 x 50 (or there-abouts)
  2. step1

  3. Make sure to set the canvas color as "transparent"
  4. Mock-up your button shape
  5. step2

  6. Use the pen tool to trace it into a single shape
    step3

    I take the individual components from the last step, group them together, and lock them, and then trace around them with the pen tool. There's probably a better way, but this is the way I know. Use the guides to help you tweak it until you are satisfied

  7. Trace a smaller version of the button inside of the outline using the pen tool
  8. Fill in the inner button, and remove the line on it
  9. Fill in the outer button
  10. step4

    If the shape looks how you want it at this point, move on, otherwise, rinse and repeat...

  11. Color the button the way you want it
    step5

    The way I do this is to fill the outside shape with a dark grey (at the top) to light grey (at the bottom) linear gradiant with a 1px solid dark grey border (a little darker than the darkest part of the gradient). Then fill the inside shape with a custom linear gradient. This is the part that requires finesse. If you want it to look like an Apple button with the slick horizon line, start light, get progressively darker, and then in one pixel make a stark jump to the darkest shade of the color you are using, then get progressively light again.

    step5gradient

  12. Add a drop shadow to the inner shape
    step5dropshadow

    Click the inner shape. Click the "+" next to "Filters" in the Properties inspector. Select "Shadow and Glow > Drop Shadow". I've selected a distance of 2, Opacity of 100%, Softness of 1 and Angle of 267.

  13. Decide on the stretching points of your button

    Pick a point in the middle of the image where if that one pixel got stretched (repeated over and over again) to widen the button, it would look good (I chose 15px for the button I've been creating for this tutorial). Pick a point in the middle of the image where if that one pixel got stretched to lengthen the button, it would look good (I chose 27px for the button I've been creating for this tutorial). Make note of these two points as you will need to know them later.

  14. At this point you have completed the "up" state for the button.

  15. Save your file (I saved as "customButtonImageDefault.png")
  16. "Save As" and rename your file for the pressed or "down" state for the button (I saved as "customButtonImageDown.png")
  17. Choose a color for the downstate, and change each gradient point to a shade of that color.
    step6

    It makes it easier if you click the color wheel in the color chooser and use the slider on the right. Also, once you have chosen your base color after clicking the color wheel and adjusting the slider, click "Add to Custom Colors" so you don't have to re-find your base color again and again each time. You can just select it from the custom colors list at the bottom left of the color wheel menu and then use the slider to choose another shade of that color. Make sure not to move any of gradient points or they won't match up with the points you took note of earlier. Up states and Down states can have different stretch points if you want since you define each state's stretch points individually in the code, but it makes it easier if you just use the same points for up and down.

  18. Once you have edited all of the points. Open the images in fireworks and switch back and forth between them to compare how it's going to look when the button is pressed. When satisfied, save. Now you're ready to get to coding!
  19. custombuttonimagedefaultcustombuttonimagedown

Creating a Custom Re-sizable Button in an iPhone App

Ok, now that you've gotten your button created, it's time to implement it.

I expect you to already know how to create I phone apps, but if not, here are un-annotated pictures of me building the scaffolding to hold our custom buttons. Following the images are the explanation on how to use custom buttons.

Creating the Scaffolding to place the custom button in

Again, if you already have an app you are trying to use the custom button in, skip this step...

buttontutorial1buttontutorial2buttontutorial3buttontutorial4

Making the Custom Button in the iPhone App

  1. Open the interface builder and click on the button you would like to customize
    buttontutorial5
  2. Open the "Button Attributes" pane (Apple + 1)
  3. For "type" select "Custom"
    buttontutorial6

    At this point, if you didn't give the button a title, it will disappear (which is ok). If you need to find it and can't, in the main window (titled yourFileName.xib) there will be several objects. Expand the one that says "View" (or wherever you put your button) and you should see your button. Clicking on it there will highlight it in the layout window.

  4. Hold down "ctrl" and drag from the "File's Owner" object to the button.

    This can all be done from within the .xib window by switching to "list" view mode

  5. In the little context menu that pops up, select "customButton" (or whatever you called the button in your code)
    buttontutorialconnectbuttontooutlet
  6. Switch to the "size" window (Apple + 3)
  7. Set the size to at least 100 x 100
    buttontutorialbuttonsize

    This is just so we can see our image stretch. When you are doing this in a non-tutorial setting, you will probably not set this at all.

  8. Switch to the "Attributes" window (Apple + 1)
  9. In the "View" section (at the bottom), click on "Background"
    buttontutorialclickbackground
  10. In the "color" window that pops up, set "Opacity" to "0" (zero)
    buttontutorialopacity
  11. Switch back over to Xcode
  12. Locate your button files and drag and drop them into the "Resources" folder of your project
    buttontutorial7

    You will probably want to make sure and click the "Copy items into destination group's folder" button

  13. Click "Add" in the pop-up that appears
  14. Switch to your view controller file

    (the one that corresponds with the view you were just editing in the Interface Builder. The one that ends with ".m")

  15. Add the following code to the -(void)viewDidLoad{} method:

    buttontutorial8

    UIImage *buttonImageNormal = [UIImage imageNamed:@"customButtonImageDefault.png"];
    UIImage *stretchableButtonImageNormal = [buttonImageNormal stretchableImageWithLeftCapWidth:12 topCapHeight:0];
    [customButton setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];

    UIImage *buttonImagePressed = [UIImage imageNamed:@"customButtonImageDown.png"];
    UIImage *stretchableButtonImagePressed = [buttonImagePressed stretchableImageWithLeftCapWidth:12 topCapHeight:0];
    [customButton setBackgroundImage:stretchableButtonImagePressed forState:UIControlStatePressed];

    The first block of code defines the image for the normal (up) state of the button. The second block defines the image for the pressed (down) state of the button. The first line of each block loads the button image for that state into the app. The second line of each block you can set the stretch points of the button (you should have noted these earlier when you made the button). You can keep setting these to different things and viewing the result to refine until you like what you see. The third line assigns the now stretchable image to the actual button. If you have more than one button you want to assign the image to, just copy the third line and replace "customButton" at the beginning with the name of the next button you want to assign the image to:


    UIImage *buttonImagePressed = [UIImage imageNamed:@"customButtonImageDown.png"];
    UIImage *stretchableButtonImagePressed = [buttonImagePressed stretchableImageWithLeftCapWidth:12 topCapHeight:0];
    [customButton setBackgroundImage:stretchableButtonImagePressed forState:UIControlStatePressed];
    [anotherCustomButton setBackgroundImage:stretchableButtonImagePressed forState:UIControlStatePressed];
    [thirdCustomButton setBackgroundImage:stretchableButtonImagePressed forState:UIControlStatePressed];

    In this way, you can assign the image to as many buttons as you want.

  16. Your viewDidLoad method should now look something like this:


    -(void)viewDidLoad {
    UIImage *buttonImageNormal = [UIImage imageNamed:@"customButtonImageDefault.png"];
    UIImage *stretchableButtonImageNormal = [buttonImageNormal stretchableImageWithLeftCapWidth:12 topCapHeight:0];
    [customButton setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];

    UIImage *buttonImagePressed = [UIImage imageNamed:@"customButtonImageDown.png"];
    UIImage *stretchableButtonImagePressed = [buttonImagePressed stretchableImageWithLeftCapWidth:12 topCapHeight:0];
    [customButton setBackgroundImage:stretchableButtonImagePressed forState:UIControlStatePressed];

    [super viewDidLoad];
    }

  17. Now hit Apple + R to compile, run and view the output!
    buttontutorialcomplete

A good amount of the information for this article came from
Beginning iPhone Development: Exploring the iPhone SDK. It's an excellent book. By far the best iPhone development book out there right now. It's really easy to read and understand. Each chapter is one or two example projects from start to finish, step by step, wonderfully explained. After buying this book I had my first iPhone App up and running within a week. The thing they don't talk about (that I did) was actually creating the button image, and dealing with the opacity. Again, all of the files for this tutorial can be downloaded from here. Feel free to leave any feedback/questions/whatever in the comments... Good luck!

1Jun/090

Print Media Alternate Style Sheet (CSS)


If you don't want to create an entirely new alternate style-sheet just for print media, there is an easier way to do it.

I had a small adjustment I needed to make for printing a page on my site, and rather than creating an entirely new (duplicate) alternate style-sheet just for print media, I discovered a neat little CSS method you could use to put the print style right in with the main style.

It's the @media print CSS method.

My original CSS code was as follows:

#dragLayer {
height:255px;
left:72px;
overflow:hidden;
position:absolute;
top:0px;
width:255px;
z-index:100;
}

For some reason the "Drag Layer" div was appearing over-top the image contained in a sub-div. I'm using scriptaculous to display a blown up version of an image when you hover over a smaller version of the image. But when you print, the smaller version of the image doesn't show up. Making the dragLayer div display equal to none didn't work for some reason. So instead I defined a print stylesheet with the dragLayer div's height and width equal to 0. I didn't want to have to make an entirely new duplicate stylesheet just for this one little CSS change for printing, so after some exploring I found the @media print css directive. Here is the style I ended up with:

#dragLayer {
height:255px;
left:72px;
overflow:hidden;
position:absolute;
top:0px;
width:255px;
z-index:100;
}

@media print{
#dragLayer{
height: 0px;
width: 0px;
}
}

This little trick was mentioned in passing in page 210 of Elizabeth Castro's
HTML, XHTML, and CSS, Sixth Edition (Visual Quickstart Guide), but Elizabeth claims it isn't as widely supported or well known as the other standard methods of doing this. In all of my testing so far, however, it looks like it works in all of the newest versions of three of the major browsers (FF, IE & Chrome).

7Oct/088

HTML E-Mail with PHP: 5 Pointers to Get ‘er DONE!

Sending e-mail can be pretty useful with PHP. It's also really easy... until you want to send HTML that is.

I used these two tutorials to learn how to send HTML e-mails in PHP:

sitepoint.com advanced e-mail tutorial
webcheatsheets.com sending e-mail tutorial

For something that requires very strict accurate guidelines to be followed, you would think they wouldn't just gloss over them or ignore them entirely. But they did.

So, here are five pointers to get you off on the right foot:

1. Use Content-Type: multipart/alternative; with a random hash

Don't just send the e-mail as HTML. Many e-mail providers don't allow for HTML e-mails, so you need alternative content. You will need a boundary string, but you will also want it to be random hash. Why? Well, I'm not really sure. I can easily imagine one scenario, which would be that if you are sending mail on behalf of someone, and they figure out your static boundary string, they could do some sort of injection attack and send some nasty thing through with your e-mail. Not really sure if this would work, or if this is the reason, but everyone else uses a random hash, so you should too!

<?php
//create a boundary string. It must be unique 
//so we use the MD5 algorithm to generate a random hash
$random_hash = md5(date('r', time())); 
//define the headers we want passed. Note that they are separated with \r\n
$headers = "From: webmaster@example.com\r\nReply-To: webmaster@example.com";
//add boundary string and mime type specification
$headers .= "\r\nContent-Type: multipart/alternative; boundary=\"PHP-alt-$random_hash\"";
?>

2. Don't use HEREDOC syntax

At first I was trying to just do this:

$msg <<<HERE
--PHP-alt-$random_hash
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

Plain text stuff

--PHP-alt-$random_hash
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

<html>
<body>
<p>
Blah blah blah $var blah!
</p>
</body>
</html>
--PHP-alt-$random_hash--
HERE;

But it just wouldn't work! I figured out you have to do it like this:

$message = "--PHP-alt-$random_hash\n\r" .  
"Content-Type: text/plain; charset=\"iso-8859-1\"" .  
"Content-Transfer-Encoding: 7bit\n\r" .  

"Hello World!!! \n\r" .  
"This is simple text email message. \n\r" .  

"--PHP-alt-$random_hash\n" .  
"Content-Type: text/html; charset=\"iso-8859-1\"" .  
"Content-Transfer-Encoding: 7bit\n\r" .  

"<h2>Hello World!</h2>\n\r" .  
"<p>This is something with <b>HTML</b> formatting.</p> \n\r" .  

"--PHP-alt-$random_hash--";

Pay special attention to where you are putting your \ns and \rs!!!

3. Get the from right!

When building your headers, don't forget to include a from. This will make your e-mail more recognizable and professional. Don't just include the from though, include a human readable value as well!

$headers = "From: An actual name <email@email.com>\r\n";

4. Don't forget those trailing "--" after the final bondary!

Don't forget those last two dashes on your final boundary:

--==Multipart_Boundary_{$semi_rand}x--

See them there at the end? You don't put those on the others, so they are easy to forget on the final one. Also, it's boundary with an "a", not "boundry"... Yeah, I misspelled it the first time...

5. If things aren't working, experiment

It took me a good hour and a half to get this working right. It all came down to those little \r and \n things in the end. I had to carefully add and remove them from different places until I got everything just right. The webcheatsheet code conveniently uses some buffer trickery to avoid this, but my web host does not support that, so I had to figure it all out myself. Here is a version of their code that actually works on my web hose (Dreamhost):

<?php
//define the receiver of the email
$to = 'email@gmail.com';
//define the subject of the email
$subject = 'Test HTML email'; 
//create a boundary string. It must be unique 
//so we use the MD5 algorithm to generate a random hash
$random_hash = md5(date('r', time())); 
//define the headers we want passed. Note that they are separated with \r\n
$headers = "From: webmaster@example.com\r\nReply-To: webmaster@example.com";
//add boundary string and mime type specification
$headers .= "\r\nContent-Type: multipart/alternative; boundary=\"PHP-alt-$random_hash\""; 
//define the body of the message.
$message = "--PHP-alt-$random_hash\n\r" .  
"Content-Type: text/plain; charset=\"iso-8859-1\"" .  
"Content-Transfer-Encoding: 7bit\n\r" .  

"Hello World!!! \n\r" .  
"This is simple text email message. \n\r" .  

"--PHP-alt-$random_hash\n" .  
"Content-Type: text/html; charset=\"iso-8859-1\"" .  
"Content-Transfer-Encoding: 7bit\n\r" .  

"<h2>Hello World!</h2>\n\r" .  
"<p>This is something with <b>HTML</b> formatting.</p> \n\r" .  

"--PHP-alt-$random_hash--";

//send the email
$mail_sent = mail( $to, $subject, $message, $headers );
//if the message is sent successfully print "Mail sent". Otherwise print "Mail failed" 
echo $mail_sent ? "Mail sent" : "Mail failed";
echo $message;
?>

Have fun! Feel free to comment if you have any other tips/questions.

Tagged as: , , , 8 Comments
4Oct/0817

Auto Upload File on Save in Aptana

This is an explanation on how to automatically upload a file via FTP when you click "save" in the Aptana IDE (2.x does not work in 3.x). Let's jump right in...

1. If you don't have a project, create one. 

2. If you don't have a "scripts" folder in your project, create one (I put mine in the root directory of my project. No clue if it will work from anywhere else). 

3. Create a new file inside your scripts folder with a .js extension (I named mine "upload_current_file_on_save.js", not sure if it will work with any other name). 

4. Place this code inside the file: 

 

Code:
/* 
 * Menu: gMan > Upload On Save 
 * Kudos: Ingo Muschenetz 
 * License: EPL 1.0 
 * Listener: commandService().addExecutionListener(this); 
 * DOM: http://localhost/com.aptana.ide.syncing 
 * DOM: http://download.eclipse.org/technology/dash/update/org.eclipse.eclipsemonkey.lang.javascript 
 */  

// Add  * Listener: commandService().addExecutionListener(this); to the top of this file to enable it 

/** 
 * Returns a reference to the workspace command service 
 */ 
function commandService() 

   var commandServiceClass = Packages.org.eclipse.ui.commands.ICommandService; 
    
   // same as doing ICommandService.class 
    var commandService = Packages.org.eclipse.ui.PlatformUI.getWorkbench().getAdapter(commandServiceClass); 
    return commandService; 

/** 
 * Called before any/every command is executed, so we must filter on command ID 
 */ 
function preExecute(commandId, event) {} 

/* Add in all methods required by the interface, even if they are unused */ 
function postExecuteSuccess(commandId, returnValue) 
 { 
    
   // if we see a save command 
   if (commandId == "org.eclipse.ui.file.save") 
   { 
      sync.uploadCurrentEditor(); 
       
      /* Replace above line if you'd like to limit it to just certain projects 
      var fileName = editors.activeEditor.uri; 
      if(fileName.match(/projectName/ig)) 
      { 
         sync.uploadCurrentEditor();    
      } 
      */ 
    } 

function notHandled(commandId, exception) {} 

function postExecuteFailure(commandId, exception) {}

 

5. Save the file. 

A few notes on what needed changed in this file from the sample file I took this from: 

1. I added this line of code to the comment block at the top: 

 

Code:
 * Listener: commandService().addExecutionListener(this);

 

I know there is a comment in this file that tells you to "add this to the top of this file", but since I'm new to the whole scripts thing I didn't get that when it said "top of the file" it meant "the middle of the comment block at the top of this file". I thought I was literally supposed to make that line the very first line in the file... Which didn't work at all... 

2. I changed the "menu" line to: 

 

Code:
 * Menu: gMan > Upload On Save 


from: 

 

Code:
 * Menu: Synchronize > Upload Current File On Save Enabled

 

For some reason it didn't work until I changed this line. Since my project is code named "gMan" (It's a user management system, you'll make the connection...) I just named the menu item "gMan" after my project. Then the command is to upload on save, so that's what I named it. As soon as I made this change is when the whole thing started working. Could be coincidence, or could be that you have to do this for the script to work (rename the menu command something other than what the sample is named). 

In case you haven't figured it out, you run the script by going to the "Scripts" menu in the toolbar at the top of Apatan (and selecting the script, whatever you named it in the previous step). 

Want to read more about website creation in Aptana from this author? Check out his book:
HTML, XHTML, and CSS All-in-One Desk Reference For Dummies (For Dummies (Computer/Tech)). Support the Author of this post and buy the book from Amazon by clicking on the link on this page. Thanks for the help!

16Sep/083

phpbb3 & zen cart integration

I've been trying to get the phpbb3 & zen cart integration to work.

I've had some errors in the default SQl zen cart comes with. First I was getting an error about an invalid column name in the phpbb_user_groups table (specifically the group_description column not existing). Once I fixed that, I got a very cryptic "1062 Duplicate entry '' for key 2" error every time I tried to create a new user.

Here's how to fix BOTH of these problems:

Problem 1 - "column group_description does not exist":

Edit line 196 in store>includes>classes>class.phpbb.php. Change "group_description" to "group_desc"

Problem 2 - 1062 Duplicate entry '' for key 2:

Edit line 187 (in the same file as in Problem 1). Change it from:

(user_id, username, user_password, user_email, user_regdate)

to:

(user_id, username, user_password, username_clean, user_email, user_regdate)

Edit line 189. Change it from:

('" . (int)$user_id . "', '" . $nick . "', '" . md5($password) . "', '" . $email_address . "', '" . time() ."')";

to:

('" . (int)$user_id . "', '" . $nick . "', '" . md5($password) . "', '" . $nick . "', '" . $email_address . "', '" . time() ."')";

phpbb requires that each user have a unique "username_clean". This is the second "key" in the table requirements. The first creates an index on user_id, the second requires username_clean be UNIQUE, the third creates an INDEX on user_birthday, and so on. In fact, at NO POINT do they EVER REQUIRE THE USERNAME TO BE UNIQUE! WHAT????? yep. It's username_clean that must be unique. zen cart doesn't even try and insert anything into username_clean, it just tries to make the username (this makes no sense at all!!!).

Feel free to comment if you have any insights/questions!

15Sep/0812

SPE (Python IDE) for Windows


I've been playing with Python this weekend. Currently I'm rebuilding "Clink" in Python instead of finishing it in Flash (It really needs AS 3.0 to do properly, and I only have access to 2.0).

The book I am reading (Game Programming: The L Line, The Express Line to Learning) recommeds the SPE (Stani's Python Editor) IDE for creating Python programs. However, the book doesn't really say how to get the program. Stani (the IDE's author) doesn't appear to have a web page with a "download" link and instructions; so here's a download link with instructions from me instead (this is for installing on Windows):

 

Step 1: Download & Install wxPython (NOT wxWidgets!!!!)

The book states that you should download and install wxWidgets. It turns out, you need wxPython instead, which you can get here:

http://www.wxpython.org/download.php

Scroll down and get the version that matches your version of Python. Just double click the downloaded file, and it basically installs itself. I won't give you any advice on what boxes to check at the end of the install, because I don't remember what they said, and to be honest, I arbitrarily made my choices having no clue as to why I was choosing what I chose (I unchecked the top one, and left the bottom two checked).

Step 2: Download and Install SPE

Go to http://developer.berlios.de/project/showfiles.php?group_id=4161

Get this file: SPE-0.8.4.c-wx2.6.1.0-no_setup.zip

Unzip it to somewhere you will remember (I put mine in Program Files) but don't rename the folder anything other than "_spe".

Go inside the _spe directory you just created and double click SPE.py

At this point your shiny new Python IDE should start up. If not, sorry... I don't know why it didn't work. Make a shortcut to the editor on your desktop for easy opening (or start menu, or quicklaunch toolbar).

Have fun!

13Sep/0824

Installing Python (mod_python) on XAMPP (on Windows)

So you want to get Python working with XAMPP eh? Me too! So, apparently, do a lot of people; and pretty much no one who knows how is saying how from what I've found online in my cursory 5 minute search. Let's just jump right in, shall we?

Resources:

Step 0: Install XAMPP & Python

You should have installed XAMPP already, but if you are a brand new "b" to the Server Side Dev ring, and you have stumbled upon this post looking for the catch all solution to getting your feet wet with Server Side Programming and have picked Python as your poison, go get XAMPP! It basically installs and configures itself, and there is an excellent tutorial on the apachefriends website to get you through this process:

http://www.apachefriends.org/en/xampp-windows.html#641

You might not have installed Python already (although, if not, why did you choose Python over PHP or Ruby?). If you haven't installed it already, go download and install it now:

http://www.python.org/download/

Step 1: Make a Backup

If you are like me, and have a few years worth of stuff in your XAMPP directory that you don't want to 'splode when you screw up the first time you try to get Python working with XAMPP, go ahead and just zip c:\xampp to x:\xampp-backup.zip now...

Step 2: Download mod_python

Download mod_python now...

http://httpd.apache.org/modules/python-download.cgi

Wait, which one do I download?

Good question! Check your version of Apache and Python to determine which one you need

  1. Enter the text (leave out the space between phpinfo and ()):
    <? phpinfo (); ?>
    into a new text document in notepad.
  2. Save the document as "test.php" (or something) in the htdocs directory of your xampp install.
  3. Start Apache (open the xampp control panel, c:\xampp\xampp-control.exe, and click "Start" next to Apache).
    NOTE: If you have IIS running, stop it. (Control Panel, Administrative Tools, Services, IIS Admin, Stop (say yes to stopping those other services too). If you scroll up to "Apache" at this point and click on it, you will see which version you are running and can skip to the next step in the mod_python install).
  4. Browse to the document you saved in step 2 through your web browser (localhost\test.php). You can NOT just double click the file and expect it to be parsed by apache and run...
  5. Scroll down and view the output in the "apache2handler" section. The first box in the table should be "Apache Version" and should tell you which version of Apache you are running (mine is 2.2.4, so I downloaded the very last ".exe" file so that I would have Python 2.5 w/ Apache 2.2)

Step 3: install mod_python

  1. Double click the exe file
  2. Click "Next"
  3. It should find your Python install. If you have more than one version, select the one you want to use. Click "Next"
  4. Click "Next"
  5. There should be a pop-up asking where Apache is installed. If you installed xampp to c:\, then this will be c:\xampp\apache

Step 4: Configure Apache

  1. Open c:\xampp\apache\conf\httpd.conf
  2. Scroll down to the section with all the "LoadModule" lines (about line #67) and add this line:
    LoadModule python_module modules/mod_python.so

    Note: If you are unable to start Apache after this, go back and type the line in the conf file by hand instead of copying/pasting.

  3. Scroll down to the section with the <Directory "/xampp/htdocs"> tag ends (about line #232) and add these lines following the closing </Directory> tag:
    <Directory "/xampp/htdocs/test">
            AddHandler mod_python .py
            PythonHandler mptest
            PythonDebug On
    </Directory>
  4. Save and close the file.
  5. Restart Apache
  6. Create a new file (and folder) c:\xampp\htdocs\test\mptest.py
  7. Place the following text in the file, and save it (watch your formatting, Python is whitespace sensitive!):
    from mod_python import apache
    
    def handler(req):
    	req.content_type = 'text/plain'
    	req.write("Hello World!")
    	return apache.OK

Step 5: Testing Py!

Point your browser to http://localhost/test/mptest.py

You should see "Hello World!". If you don't, check this page out (and this one and this one). Also, make sure you got the path correct in the <Directory /> tag, and saved your mptest.py file to the right place.

What's next? Why not get a Python book? This one is really good:
Game Programming: The L Line, The Express Line to Learning (The L Line: The Express Line To Learning). That's right! Game programming in Python.

Or, why not check out some tutorials, starting with this one! (and check out this presentation on django)

Edit:

Some user comments:

<Directory /test> ... </Directory> <-- This is wrong!

But, the following works:

<Directory "C:/xampp/htdocs/test"> ... </Directory>

instead on adding the directory block, which turns on mod-python for a single folder, add the following at the end of the file (assumes you want to use the Publisher handler):

<IfModule python_module>
AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On
</IfModule>

If you have any other comments that require code. Just send me an e-mail (cmcculloh-at-gmail-dot-com) and I'll post the code (so you don't have to worry about it getting mangled).