Clickbank Security Using PHP

Written by Robert Plank

Continued from page 1

Here we can say, 30 days after someone buys your product,repparttar thank you page will be inaccessible to them. If they buy on October 25th, they can bookmark and revisit that thank you page up until November 25th atrepparttar 107756 exact time they made their purchase. It's kind of a nice compromise because it gives honest people enough time to get what they need but atrepparttar 107757 same time it becomes impractical to sharerepparttar 107758 URL.

In chapter 9 of my book, Simple PHP (, I explained how time works on computers, they use a big number which is just a count of how many seconds have passed since January 1st, 1970. I also explained that there was a function, called strtotime(), which we could use to determine this "number" or timestamp of a certain date. For example, 30 days ago or 1 year ago.

30 days sounds about right. To figure outrepparttar 107759 Unix timestamp of this moment, minus 30 days is:

strtotime("-30 days")

Now, to store it in a variable called $expire:

$expire = strtotime("-30 days");

But you're saying, how do I know when these people purchased? I don't have that kind of information. Aha! But you can. Remember,repparttar 107760 seed you put in your order links can be anything you want. So let's just make itrepparttar 107761 timestamp of this exact moment.

Whenrepparttar 107762 customer revisitsrepparttar 107763 thank you page, they can't changerepparttar 107764 seed, because as I mentioned, if you change *either*repparttar 107765 seed orrepparttar 107766 secret key,repparttar 107767 resulting hash (proof of purchase) will be different. So you see, they're stuck with it. But,repparttar 107768 current time always changes!

All we have to do, in cb.php, are these two steps:

* Figure out whatrepparttar 107769 timestamp was exactly 30 days ago, and store this value in $expire.

* Comparerepparttar 107770 seed and $expire. Ifrepparttar 107771 the value ofrepparttar 107772 seed is less than that of $expire, it means thatrepparttar 107773 product was purchased more than 30 days ago andrepparttar 107774 visitor shouldn't be given access torepparttar 107775 page. Die.

We've already taken care of step one by savingrepparttar 107776 timestamp 30 days prior in $expire. Now, we comparerepparttar 107777 seed (it's $_GET["seed"], remember, because we're grabbing it out ofrepparttar 107778 URL string) and $expire like:

if ($_GET["seed"] < $expire)

And finally plug it intorepparttar 107779 if-statement before that checkedrepparttar 107780 hashes:

if ($_GET["seed"] < $expire or !cbValid($_GET["seed"], $_GET["cbpop"], $secret_key)) die();

We've got that part taken care of, now forrepparttar 107781 home stretch. We've got to actually get those seeds to berepparttar 107782 current time. How do we do that? Again,repparttar 107783 pages containing your order link will have to be renamed to end in ".php". Hey, you'rerepparttar 107784 one who wants to prevent theft.

Let's pretend this is a Clickbank link:

Order Now

Instead of YOUR_SEED we want PHP to callrepparttar 107785 function mktime(), which gives usrepparttar 107786 current timestamp, and output it, using echo.

echo mktime();

Now just put around it...

And shove it in there.

Order Now

Now setup a link for $0.00 in your Clickbank control panel and try it. You can be sure it works by changing that "-30 days" in strtotime to "-5 minutes". Then try accessingrepparttar 107787 download page, then wait 5 minutes and try again. Neat, isn't it?

You say, I've done this, but I have more than one product. How do I keep someone from grabbing everything once they've grabbed one?

Have your links look likerepparttar 107788 following: Order Now

This wayrepparttar 107789 seeds will look like "stringbeans445433" if you're selling stringbeans. Then again if you're selling corn onrepparttar 107790 cob on another sales page, you can change "stringbeans" to "cornonthecob". Nowrepparttar 107791 seeds for each product will be different.

Those seeds won't be all numbers, will they? So, in cb.php, do this:

$timestamp = ereg_replace("[^0-9]","",$_GET["seed");

I won't go into a lot of detail about pattern matching, butrepparttar 107792 [^0-9] means "NOT anything from 0 to 9. It basically goes through every letter and number of $_GET["seed"], and if what's there isn't a 0, 1, 2, etc. it's replaced with nothing (hencerepparttar 107793 ""). The final result is saved in a variable called $timestamp.

Since now we're looking at $timestamp and not $_GET["seed"], let's change that if-statement:

if ($timestamp < $expire or !cbValid($_GET["seed"], $_GET["cbpop"], $secret_key)) die();

Now it checks with $timestamp instead of $_GET["seed"].

One last thing I implemented in here was a little something that keeps a customer from paying for one of your products, and getting access torepparttar 107794 rest. Look at this part of that order link I gave you:


When I extractedrepparttar 107795 timestamp fromrepparttar 107796 seed, I simply removed all characters that were not numbers, leaving justrepparttar 107797 numbers contained within that string. Now I want to dorepparttar 107798 opposite. Here's an example seed:


I take out allrepparttar 107799 numbers and am left with "test". Next I figure out which script called cb.php (which is stored inrepparttar 107800 variable $_SERVER["SCRIPT_NAME"]). Thenrepparttar 107801 script takes out everything up torepparttar 107802 last slash (/) and everything beforerepparttar 107803 first dot (.). Ifrepparttar 107804 script was located at "/clickbank est.php", all that's left is "test".

If you give each thank you page a different name, and make sure all your seeds reflectrepparttar 107805 correct page, i.e. if your thank you page is called "carrots",repparttar 107806 part of that order link containingrepparttar 107807 seed should appear as:


If you don't care how Clickbank's protection works, that's your derogative. Just getrepparttar 107808 zip file and followrepparttar 107809 instructions I've provided in cb.php.

As far as scripts that handle several Clickbank products -- I can't recommend any at this time, since I've never across any good ones. (But you should check out Harvey Segal's free site,, which can answer most of your questions about Clickbank.)

Here's that script again in case you missed it: utorials/clickbank/

Make sure to readrepparttar 107810 instructions I've supplied in cb.php, get everything setup and on your web server, and you'll be well on your way to having bulletproof protection on your Clickbank products.

Robert Plank is the creator of Lightning Track, Redirect Pro, Rotatorblaze, and other useful tools.

Want to pick up more programming skills? Then purchase the e-book "Simple PHP" at

You may reprint this article in full in your newsletter or web site.

HTACCESS Wrappers with PHP

Written by Robert Plank

Continued from page 1

$file = $_SERVER["PATH_TRANSLATED"]; readfile($file);



To makerepparttar HTTP compression work, we use two functions: ob_start() and ob_gzhandler(). Output buffering functions are strange. Any time you try to display something, you can have PHP save up everything you're trying to output. Atrepparttar 107755 very end it's all dumped into a function of your choosing whererepparttar 107756 text can be changed or transformed before it's output.

There is a built-in PHP function called ob_gzhandler() which takes one parameter (a string of text), compressesrepparttar 107757 data according torepparttar 107758 gzip standard and does allrepparttar 107759 header trickery that's needed to tellrepparttar 107760 user's browser that we are transmitting data that needs to be decompressed once it's downloaded. When this line is used:


It tells PHP: everything displayed afterwards has to go throughrepparttar 107761 function ob_gzhandler() first. Put that atrepparttar 107762 top of our script and here's what we've got:

ob_start("ob_gzhandler"); $file = $_SERVER["PATH_TRANSLATED"]; readfile($file);


Save that as compress.php. Upload both files, chmod htaccess.txt to 0755 and rename to .htaccess and you're done. That's all you need for it to work, and you can just as easily apply HTTP compression to any script by just adding that line.

To try this puppy out, I got on a dialup connection and put a copy of "The Decline And Fall Of The Roman Empire Volume 1" on my web host, a 900 page book, about 1.6 megabytes in size. Without HTTP compression it took 5 and a half minutes to download. Withrepparttar 107763 compression, only 2 minutes. Internet Explorer told merepparttar 107764 download was going at 20 KB per second, impossible with a dialup connection... but sincerepparttar 107765 file was zipped, I really was downloading 20 KB a second (oncerepparttar 107766 data was decompressed on my end) over a 5 KB per second connection.

Though HTTP compression will work on sounds, video, and images,repparttar 107767 space you save is negligible, usually only a few bytes. These sorts of media are already heavily compressed so zipping makes almost no difference. This is why we've told htaccess to only use compression on text and HTML, because it's with human languages like English where a lot of repetition occurs, which means more information can be compressed.

Not all browsers support HTTP compression, but ob_gzhandler() figures out if a browser can support HTTP compression. Ifrepparttar 107768 browser doesn't,repparttar 107769 original file is displayed, no harm done.

You can get a copy of this sample script at: utorials/wrapper/

Both of these scripts I've created for you will work only on static files, files that actually exist such as images or HTML files. If you tried to apply these wrappers as-is to PHP scripts, Perl scripts or even HTML pages that use SSI. If your whole site is run by a single script it's a better idea to hard-code these things right in, anyway.


This last demonstration of an htaccess wrapper is something that I think most people with content sites have a use for. Onrepparttar 107770 Internet, people steal stuff. Theft of HTML source code is a nuisance, sure, butrepparttar 107771 lifting of images is more common. Someone likes a logo on your page, or an e-book cover, or a picture of a physical product you're selling, and it becomes theirs to use.

A practical way to keep this from happening is to add a watermark to all your images, which is your logo or name on a corner somewhere, forcing anyone who takes your graphic to either unwillingly give you credit, or chop off a part of that picture.

Lucky for us, PHP has a set of functions to handle images, and in version 4.3 and above, it's included by default. Wrappers come in handy here because you might have an entire site full of images and would rather not spend three weeks watermarking tons of images by hand. Maybe you just don't want to have to juggle two sets of images, one watermarked and one normal.

Download this script from: utorials/wrapper/

The only files you need to worry about in that zip are htaccess.txt and wrapper.php. Upload them to a folder called "watermark", chmod htaccess.txt to 0755 and rename to ".htaccess".

The file wrapper.php remain as is. I've put comments inrepparttar 107772 file regarding most of what it does, so if you're curious go ahead and take a peek.

Whatrepparttar 107773 script does is this: It figures outrepparttar 107774 original image that was supposed to be called. Then it loadsrepparttar 107775 watermark, which I've set in wrapper.php to be "watermark.png" which is just a PNG image containingrepparttar 107776 text "THIS IS WATER MARKED". The watermark is placed on top ofrepparttar 107777 original, inrepparttar 107778 lower right corner, and output inrepparttar 107779 same format (i.e., JPEG) asrepparttar 107780 original.

You can tellrepparttar 107781 difference by looking at these two images: utorials/wrapper homas.jpg utorials/wrapper homas-watermarked.jpg

I've included several types of images (GIFs, JPGs, and PNGs) inrepparttar 107782 zip file for you to test out. Once you've got everything setup, upload those images and see how they look withrepparttar 107783 watermark.

This script will work with GIFs, JPEGs, and PNGs. Due to a patent issue (which expires worldwide in July 2004) GIFs can only be read, and not output. To make up for this, any of your GIFs will be output as PNGs, which should still work.


If you think about it, a watermark script like this could also be used for a number of things. For example, if you decide to run an image hosting service like AuctionWatch does for eBay users, you could watermark your site's URL torepparttar 107784 bottom. Your users get a free service and everyone else sees a possible place to get free image hosting, there's some nice viral promotion right there.

You could also adaptrepparttar 107785 script to checkrepparttar 107786 HTTP referer (inrepparttar 107787 variable $_SERVER["HTTP_REFERER"]) to see ifrepparttar 107788 image was called offsite. If it was,repparttar 107789 script would putrepparttar 107790 watermark on there but if you called it from a page on your own site,repparttar 107791 image would be shown without one.

Even I have put wrappers to good use. Last year I wrote a product for Teresa King called Codewarden, which uses htaccess wrappers to display allrepparttar 107792 files of a directory in an encoded JavaScript string in an effort to hide HTML source.

Robert Plank is the creator of Lightning Track, Redirect Pro, Rotatorblaze, and other useful tools.

Want to pick up more programming skills? Then purchase the e-book "Simple PHP" at

You may reprint this article in full in your newsletter or web site.

    <Back to Page 1 © 2005
Terms of Use