#!/usr/bin/perl -wT # # Modification History # # 2004-January-9 Jason Rohrer # Created. # Copied from DHB P2P fund. # Made separate directories for public/private data. # Fixed custom field. # Fixed refund bug. # # 2004-February-26 Jason Rohrer # Changed to format dollar amounts with two decimal places. # # 2004-March-7 Jason Rohrer # Changed to match new IPN refund format. # # This script must have write permissions to its dataDirectory # it must be able to create files in this directory # On most web servers, this means the directory must be world-writable. my $pubDataDirectory = "../htdocs/donationData"; my $privDataDirectory = "../cgi-data/donationTracker"; # If this $privDataDirectory setting is changed, you must also change it below # where the error LOG is opened # setup a local error log use CGI::Carp qw( carpout ); BEGIN { use CGI::Carp qw( carpout ); open( LOG, ">>../cgi-data/donationTracker/errors.log" ) or die( "Unable to open errors.log: $!\n" ); carpout( LOG ); } use strict; use CGI; # Object-Oriented CGI library # script settings my $donationFormURL = "http://mute-net.sf.net"; my $scriptURL = "http://mute-net.sf.net/cgi-bin/donationTracker.pl"; my $scriptFileName = "donationTracker.pl"; my $donationLogFile = "$privDataDirectory/donationLog.txt"; my $overallSumFile = "$pubDataDirectory/overallSum.html"; my $donationCountFile = "$pubDataDirectory/donationCount.html"; # where non-fatal errors and other information is logged my $logFile = "$privDataDirectory/log.txt"; # IP of notify.paypal.com # my $paypalNotifyIP = "65.206.229.140"; # New IP as of October 23, 2003 my $paypalNotifyIP = "64.4.241.140"; # end of script settings # setup stuff, make sure our needed files are initialized if( not doesFileExist( $overallSumFile ) ) { writeFile( $overallSumFile, "0" ); } if( not doesFileExist( $donationCountFile ) ) { writeFile( $donationCountFile, "0" ); } # create object to extract the CGI query elements my $cgiQuery = CGI->new(); # always at least send an HTTP OK header print $cgiQuery->header( -type=>'text/html', -expires=>'now', -Cache_control=>'no-cache' ); my $remoteAddress = $cgiQuery->remote_host(); my $action = $cgiQuery->param( "action" ) || ''; if( $action eq "showSource" ) { # print the sourcecode for our script print "
";
my $source = readFileValue( $scriptFileName );
# replace any &'s in code with &
$source =~ s/&/&/g;
# replace HTML brackets with < and >
$source =~ s/</g;
$source =~ s/>/>/g;
print $source;
print "\n";
}
# make sure the request is coming from paypal
elsif( $remoteAddress eq $paypalNotifyIP ) {
my $donorName;
# was this paypal payment generated by us?
my $customField = $cgiQuery->param( "custom" ) || '';
if( $customField eq "MUTE_donate" ) {
my $amount = $cgiQuery->param( "mc_gross" ) || '';
my $currency = $cgiQuery->param( "mc_currency" ) || '';
my $fee = $cgiQuery->param( "mc_fee" ) || '0';
my $date = $cgiQuery->param( "payment_date" ) || '';
my $transactionID = $cgiQuery->param( "txn_id" ) || '';
# these are for our private log only, for tech support, etc.
# this information should not be stored in a web-accessible
# directory
my $payerFirstName = $cgiQuery->param( "first_name" ) || '';
my $payerLastName = $cgiQuery->param( "last_name" ) || '';
my $payerEmail = $cgiQuery->param( "payer_email" ) || '';
# only track US Dollars
# (can't add apples to oranges to get a final sum)
if( $currency eq "USD" ) {
my $status = $cgiQuery->param( "payment_status" ) || '';
my $completed = $status eq "Completed";
my $pending = $status eq "Pending";
my $refunded = $status eq "Refunded";
if( $completed or $pending or $refunded ) {
# write all relevant payment info into our private log
addToFile( $donationLogFile,
"$transactionID $date\n" .
"From: $payerFirstName $payerLastName " .
"($payerEmail)\n" .
"Amount: \$$amount\n" .
"Fee: \$$fee\n" .
"Status: $status\n\n" );
if( $refunded ) {
# subtract from total sum
my $oldSum =
readTrimmedFileValue( $overallSumFile );
# fee on refunds now reported as negative
# this changed as of February 13, 2004
my $newSum = $oldSum - $amount - $fee;
# format to show 2 decimal places
my $newSumString = sprintf( "%.2f", $newSum );
writeFile( $overallSumFile, $newSumString );
my $oldCount = readTrimmedFileValue(
$donationCountFile );
my $newCount = $oldCount - 1;
writeFile( $donationCountFile,
$newCount );
}
# ignore negative completed transactions, since
# they are reported for each refund (in addition to
# the payment with Status: Refunded)
if( $completed and $amount > 0 ) {
# fee has not been subtracted yet
# (fee is not reported for Pending transactions)
my $oldSum =
readTrimmedFileValue( $overallSumFile );
my $newSum = $oldSum + $amount - $fee;
# format to show 2 decimal places
my $newSumString = sprintf( "%.2f", $newSum );
writeFile( $overallSumFile, $newSumString );
my $oldCount = readTrimmedFileValue(
$donationCountFile );
my $newCount = $oldCount + 1;
writeFile( $donationCountFile,
$newCount );
}
}
else {
addToFile( $logFile, "Payment status unexpected\n" );
addToFile( $logFile, "status = $status\n" );
}
}
else {
addToFile( $logFile, "Currency not USD\n" );
addToFile( $logFile, "currency = $currency\n" );
}
}
else {
addToFile( $logFile, "Custom field does not contain our tag\n" );
addToFile( $logFile, "custom = $customField\n" );
}
}
else {
# else not from paypal, so it might be a user accessing the script
# URL directly for some reason
# make sure we're not getting IPN from another address
my $customField = $cgiQuery->param( "custom" ) || '';
if( $customField eq "MUTE-donate" ) {
my $date = $cgiQuery->param( "payment_date" ) || '';
my $transactionID = $cgiQuery->param( "txn_id" ) || '';
my $amount = $cgiQuery->param( "mc_gross" ) || '';
my $payerFirstName = $cgiQuery->param( "first_name" ) || '';
my $payerLastName = $cgiQuery->param( "last_name" ) || '';
my $payerEmail = $cgiQuery->param( "payer_email" ) || '';
my $fee = $cgiQuery->param( "mc_fee" ) || '0';
my $status = $cgiQuery->param( "payment_status" ) || '';
# log it
addToFile( $donationLogFile,
"WARNING: got IPN from unexpected IP address\n" .
"IP address: $remoteAddress\n" .
"$transactionID $date\n" .
"From: $payerFirstName $payerLastName " .
"($payerEmail)\n" .
"Amount: \$$amount\n" .
"Fee: \$$fee\n" .
"Status: $status\n\n" );
}
# Redirect to the donation form page
print
"\n";
}
##
# Reads file as a string.
#
# @param0 the name of the file.
#
# @return the file contents as a string.
#
# Example:
# my $value = readFileValue( "myFile.txt" );
##
sub readFileValue {
my $fileName = $_[0];
open( FILE, "$fileName" )
or die( "Failed to open file $fileName: $!\n" );
flock( FILE, 1 )
or die( "Failed to lock file $fileName: $!\n" );
my @lineList =