SimpleshoPHP

Detailed Analysis - Part 7

checkout2.php

Got the Book Bag, got the credit card info -- all that's left is to send the order to someone who can fill it, and clean up. I should mention at this point that you could punt on the previous page and install a PayPal button -- but the lady who asked me to write this code went to the trouble to get an actual merchant account, which means she can process credit card orders. And so we shall.

<?
require_once("startme.inc");
if (!$PHPSESSID) {
        header("Location: main.php");
        exit;
}

Same as checkout.php -- we don't want wiseguys calling this page directly.

// <!-- here's the form data -->
$data = $full_name . "\n" . $email . "\n" . $address1 . "\n" . $address2 . "\n";
$data = $data . $address3 . "\n " . $address4 . "\n";
$data = $data . $cc_type . "\n" . $cc_num . "\n" . $cc_exp_mon . "/" . $cc_exp_yr . "\n";

The dot (".") is the PHP "concatenate" or "string-together" character. The backslash-n ("\n") is a newline; we're formatting our data nicely for the person who is going to be processing it.

// <!-- marry it to the bookbag  -->
$connection = mysql_connect("localhost", "dbusername", "dbpassword")
  	or die ("Couldn't connect to server.");
		
$db = mysql_select_db("bookstore", $connection)
	or die ("Couldn't select database.");

All stuff we've seen before....

$sql = "SELECT books.sku, title, author, format, price, bag.qty
FROM books, bag WHERE books.sku = bag.sku AND sess = '$PHPSESSID'";

Hello, bookbag code.

$sql_result = mysql_query($sql,$connection) 
	or die ("Couldn't get Book Bag");

$i = 0; $tot = 0; $tqty = 0; $item_list="\n";
while ($row = mysql_fetch_array($sql_result)) {
	$i++;
	$sku = $row["sku"];
	$title = $row["title"];
	$author = $row["author"];
	$format = $row["format"];
	$qty = $row["qty"]; $tqty += $qty;
	$price = sprintf("%0.2f",$row["price"]);
	$tot += ($price * $qty);
	$item_list=$item_list . "Book $i $sku, $title, $author, $price\n";
}
$ptot = sprintf("\$%0.2f",$tot);

Instead of formatting this onto the screen, we're going to "pipe" it into the GPG encryption program:

// <!-- format it -->
$msg = $data . "\n" . $item_list . "\n Total " . $ptot;
$msg = escapeshellarg($msg);

The escapeshellarg() function puts a backslash in front of anything that could be used to turn plain text into system commands (and wreak havoc on our server). We've glossed over a lot of editing that ought to have already been done on the fields where we let customers type things. This is our last chance to protect ourselves from that kind of sillybuggers.

// <!-- encrypt it and mail it  -->
$gpg = '/usr/bin/gpg';
$home_dir = '/var/jail/roboclerk';
$fm  = 'roboclerk@example.com';
$to  = 'orders@example.com';

I know spambots are going to scrape this page and pick off anything that looks at all like an email address, so I'm using non-addresses for this example.

$cmd = "echo $msg | $gpg --batch --no-secmem-warn --armor --home $home_dir \
 -u $fm --default-key $fm -r $to --encrypt --sign";

Here's where all the examples I've seen fall apart. You need to have a secret key with no passphrase, which should only be used to sign the outgoing mail; and it has to own a public keyring with the recipient's PUBLIC key, which has to be "trusted" -- the best way to accomplish that is to add it to the keyring in an interactive session. Catch-22; it's owned by roboclerk, an account that can't run programs and can't log in! We solve that problem by doing the work on another machine. I created a new pair of keyrings, public and private, for the roboclerk account and then copied them to the roboclerk home directory on the server, which does not have a login shell. (If most of that went right over your head, well, move on to Part 10, "Hooking it up".)

$message_body = `$cmd`;

On the demo store, this line is commented out just to keep the curious from filling my mailbox with bogus orders. The "backtick" characters "`" are a magical Unix thing that tells PHP to fill $message_body with the output it gets by running the string $cmd as a Unix command. Note well that the first thing in $cmd is not user data, but the "echo" command. The sillybuggers will no doubt find great amusement in putting various nasty things into any field they can puzzle out, trying to have some string they enter viewed by the system as a command on its own. It's my thankless job to keep that from happening.

The rest of the line is concerned with running GPG to encrypt the order information -- all the customer order information, plus a formatted copy of the bookbag contents. The result is a large block of solid text characters, thoroughly scrambled and practically impossible to decrypt without the matching private key, which does not exist on this server. That is what will be stuffed into $message_body.

Notice that we haven't sent anything to the browser yet. That means we can still do a "header" redirect, and so we shall, right after we mail this order:

mail($to,'Web Site Order',$message_body);
header("Location: tyvm.php");
exit;

Our next (and last) PHP page: tyvm.php is our "thank you very much" screen, where we will tell the customer that her order is being processed... and where we will clean up the database by removing her bookbag.


Summary

Detailed descriptions

SimpleshoPHP Home


You are invited to post comments or questions on the SimpleshoPHP forum at SourceForge.net.

SourceForge.net Logo


Copyright 2003-2005, Kevin Martin, dba Brass Cannon Consulting.
The project "SimpleshoPHP" is Free Software, distributed
under the LGPL as described at opensource.org