Hack 64 Manage Subscription Passwords the Easy Way

figs/moderate.gif figs/hack64.gif

Use PayPal's Password Management feature and a PayPal-provided Perl script to get a subscription service up and running quickly.

PayPal offers a subscription service [Hack #61] that enables you to set up your customers to pay you on a recurring basis. But if you offer access to an online resource, it can be a pain to manage all the subscribers manually. You'll have to monitor your PayPal account or email notifications, activate service each time you get a new subscriber, email customers their usernames and passwords, and deactivate the accounts of canceled subscribers precisely at each subscription's end of term. It goes on and on. That ain't any kind of fun.

If you are an experienced programmer, you can take advantage of Instant Payment Notifications (IPN) [Hack #65] to update subscriber lists and send out passwords automatically, but that requires a fair amount of knowledge, expertise, and patience. To help online merchants, PayPal offers a Password Management feature, including a complementary Perl script, that makes things much easier.

The Password Management feature takes PayPal's standard subscriptions service one step further by automatically generating usernames and passwords for your subscribers. PayPal displays the newly created username and password to each new subscriber upon signup. Subscribers should probably write them down, because they aren't memorable. For example, a username might be pp-cookankle with the password saga!glint. Occasionally, you'll get even stranger combinations!

Shortcut to the Subscription Page

Subscribers can always find their usernames and passwords in the subscription details page at the PayPal web site. You can provide your customers with a shortcut to this page with this link (where merchant_email is the email address of the merchant?in this case, you):

https://www.paypal.com/cgi-bin/webscr?cmd=_subscr-find&alias=merchant_email

The link takes each subscriber to his own History page at PayPal and shows a list of any and all subscriptions purchased from you. Merchants can also pull down a list of subscribers, including usernames and passwords, in a downloadable log.


6.5.1 .htpasswd and .htaccess

To use Password Management, you must run your own Apache web server on Unix or Linux (or use a hosting provider that offers it; the vast majority of hosts do). Password Management works with the .htpasswd and .htaccess files used by Linux/Unix and Apache, as described at http://httpd.apache.org/docs/howto/auth.html. Apache consults these password files before it allows (or denies) access to your premium content directories.

The Perl script in this hack works in conjunction with the Password Management option on the PayPal system, IPN, and your web server to automatically add and remove users from your .htpasswd and .htaccess files and thus provide immediate password-protected access to new subscribers.

PerlDiver is a useful tool when deploying Perl scripts. It tells you the path to your home directory, the path to your sendmail program, and which Perl modules are installed on your server. All three are pertinent to Password Management installation. PerlDiver is available for free at http://www.scriptsolutions.com/programs/free/perldiver/.


6.5.2 Getting the Code

Even though Perl is a programming language, you don't need to know how to program in order to install this script successfully. Familiarity with Perl is, of course, helpful, as is some experience in creating and editing files and directories on Unix or Linux systems.

It's usually possible to perform a complete installation using File Transfer Protocol (FTP)?a method of transferring files between computers?to upload the file to your server. If not, you might need to connect to your server with Telnet or SSH (or with some other server access program provided by your hosting provider). In any event, use the method with which you are most comfortable.

First, obtain the PayPal Perl script from the PayPal web site:

  1. Log into PayPal and click the Merchant Tools tab.

  2. Click Subscriptions and Recurring Payments.

    While you're here, make note of the Subscriptions Password Management checkbox. To use Password Management for a subscription, you'll need to enable this feature.


  3. Click the "IPN and server modifications" link.

  4. Click the "Download Perl script" link and save the Manual and Script to your hard drive.

The script is packed into a gzipped TAR file. Windows users can use WinZip (http://www.winzip.com) to decompress this file. Unix and Mac OS X users should go to the command line and type gunzip paypal.tar.gz and then tar xvf paypal.tar to extract the script and README file.


The complete installation instructions are too lengthy to discuss here, but the manual provided by PayPal does a decent job. Among other things, the manual covers the setup of basic authentication with Apache, installation and configuration of the script, and updates you'll need to make your PayPal account configure IPN.

The PayPal manual sometimes refers to the password file as .htpassword (as opposed to the more standard .htpasswd). This is okay; the file can be named anything you choose, so long as it is referenced properly in your Perl script and Apache configuration files.


For your reference, Figure 6-1 shows a typical directory structure for a web site. Unfortunately, every hosting provider seems to have a different naming convention and organizational structure, so this hierarchy will probably be slightly different from what you find on your web server.

Figure 6-1. A typical hierarchy of directories and files that make up a web server
figs/pph_0601.gif


If you encounter any problems, make sure your files are installed to the correct locations, that you've set the file privileges with chmod, and that the file location of your .htaccess file is specified in your paypal.pl Perl script.


Once you have everything set up, you should give it a thorough testing and then roll it out to your customers. The script will handle incoming Instant Payment Notifications and make updates to your password files automatically.

6.5.3 Adding Users Manually

In order to manage users on your web site manually, open your .htpasswd file for editing (any plain-text editor will do). You'll notice that it is made up of a long list of text strings that look like this: pp-oaktunnel:8fusre9fhs. The first part is the PayPal-generated username, the second part is a scrambled version of the password, and the two are separated by a colon (:). The PayPal Perl script automatically inserts and deletes lines in this file.

To remove a user, simply delete the corresponding line from the file. Or, to temporarily disable a subscriber's access without deleting the line altogether, just add the word OFF in front of the user's password. You can reinstate access by removing the OFF prefix at any time.

When you are just getting started with a Password Management installation, you'll probably want to set up some temporary user accounts for testing purposes. Adding a few test accounts here means that you don't have to set up secondary PayPal accounts and purchase subscriptions from yourself just to test the system.


Adding users is a little more complicated, because the passwords are scrambled with the Unix crypt() function. The easiest way to generate an encrypted password is to use a web-based tool such as the one at http://www.earthlink.net/cgi-bin/pwgenerator.pl. Next, insert the username:password combo just as you would edit any other file on your web server. If you add a username:password combination to the end of the list, make sure to press Return or Enter so that your cursor moves to the next line before you save the file.

If you want to add a user from the Unix command line (and without having to edit the .htpasswd file manually), use the htpasswd utility that comes with Apache, like this:

htpasswd -b -d /usr/web/mysite.com/.htpasswd newuser newpass

In this command, /usr/web/mysite.com is the full path of your .htpasswd file, and newuser and newpass are the username and password of the new user, respectively.

6.5.4 Hacking the Hack

There are some commonly requested enhancements to the paypal.pl Perl script that are reasonably easy and safe to perform:


Multiple currencies

The paypal.pl Perl script supports subscriptions funded by U.S. dollars (USD) only, but you can modify it to support the other currencies that PayPal uses (GBP, CAD, JPY, and EUR).


Multiple subscription terms

PayPal's Perl script handles only one set of subscription terms. However, you can add support for a more complicated pricing structure, such as discounts for longer-term commitments.

Consider the following hypothetical subscription. You'd like to charge your customers 10 euros per month, or 100 euros annually for subscribers who sign on for a full year (the annual rate provides a savings of 20 euros).

The PayPal signup button for 10 euros per month would then look like this:

<form method="post" action="https://www.paypal.com/cgi-bin/webscr">

<input type="hidden" name="cmd" value="_xclik-subscriptions">

<input type="hidden" name="business" value="pay@paypalhacks.com">

<input type="hidden" name="a3" value="10.00">

<input type="hidden" name="p3" value="M">

<input type="hidden" name="t3" value="1">

<input type="hidden" name="currency_code" value="EUR">

<input type="hidden" name="src" value="1">

<input type="submit" value="10.00 Euros per Month">

</form>

And the button for 100 euros per year would look like this:

<form method="post" action="https://www.paypal.com/cgi-bin/webscr">

<input type="hidden" name="cmd" value="_xclik-subscriptions">

<input type="hidden" name="business" value="pay@paypalhacks.com">

<input type="hidden" name="a3" value="100.00">

<input type="hidden" name="p3" value="Y">

<input type="hidden" name="t3" value="1">

<input type="hidden" name="currency_code" value="EUR">

<input type="hidden" name="src" value="1">

<input type="submit" value="100.00 Euros per Year">

</form>

To enable both of these scenarios, make the following edits to the paypal.pl script. First, replace these lines from the paypal.pl script:

# If you have an initial trial period set it here. For example one 

# month would be '1 M'

my $PERIOD1 = ''; 



# If you have a second trial period set it here. For example one 

# month would be '1 M'

my $PERIOD2 = ''; 



# Set this to your recurring or normal period. For example one 

# month would be '1 M'

my $PERIOD3 = '1 M'; 



# Set this to the dollar amount for your initial trial period. For

# example a free trial would be '0.00'

my $AMOUNT1 = ''; 



# Set this to the dollar amount for your second trial period. For

# example a $1.00 trial would be '1.00'

my $AMOUNT2 = ''; 



# Set this to the dollar amount for your recurring or normal period. 

# For example $1.00 would be '1.00'

my $AMOUNT3 = '10.00';

with this code:

# Join button a

my $PERIOD1a = '';

my $AMOUNT1a = ''; 

my $PERIOD3a = '1 M';

my $AMOUNT3a = '10.00'; 



# Join button b

my $PERIOD1b = '';

my $AMOUNT1b = ''; 

my $PERIOD3b = '1 Y'; 

my $AMOUNT3b = '100.00';



# Join button c

my $PERIOD1c = '';

my $AMOUNT1c = ''; 

my $PERIOD3c = '';

my $AMOUNT3c = '';



my $CURRENCY = 'EUR';

This example allows you to configure up to three subscription tiers; just fill in the details of your subscriptions here.

This modification doesn't support the middle subscription period, PERIOD2, which is seldom used.


Next, replace these lines:

sub validate_signup {

  # validate the terms and amounts

  if ((param("period1") ne $PERIOD1) 

    || (param("period2") ne $PERIOD2) 

    || (param("period3") ne $PERIOD3) 

    || (param("amount1") ne $AMOUNT1) 

    || (param("amount2") ne $AMOUNT2) 

    || (param("amount3") ne $AMOUNT3)) {

    error_notify("This customer did not sign-up according to your payment

       terms. Although payment was accepted the account was not activated.",

       "validate subscription terms", 0, 1);

    return undef;

  } 

}

with this code:

sub match_terms {

        # validate the terms and amounts

        my $p1 = shift;

        my $a1 = shift;

        my $p3 = shift;

        my $a3 = shift;



        if (($p1 eq param("period1") && $a1 eq param("mc_amount1")) &&

         ($PERIOD2 eq param("period2") && $AMOUNT2 eq param("mc_amount2"))&&

         ($p3 eq param("period3") && $a3 eq param("mc_amount3")) &&

                 ($CURRENCY eq param("$mc_currency"))) {

                return 1;

        } else {

                return undef;

        }

}



sub validate_signup {

        # validate the terms and amounts

        if (match_terms($PERIOD1a, $AMOUNT1a, $PERIOD3a, $AMOUNT3a) ||

         match_terms($PERIOD1b, $AMOUNT1b, $PERIOD3b, $AMOUNT3b) ||

         match_terms($PERIOD1c, $AMOUNT1c, $PERIOD3c, $AMOUNT3c)) {

        } else {

                error_notify("Although payment was accepted the account 

was not activated.",

                                "validate subscription terms", 0, 1);

                return undef;

        }

6.5.5 See Also

For information on Apache's password protection for directories and tools to modify the .htpasswd file, see Apache: The Definitive Guide by Ben Laurie and Peter Laurie (O'Reilly).

?Patrick Breitenbach and Dave Burchell