Mike Ashfield
Mike Ashfield

Reputation: 91

PayPal IPN development

I'm having some moderate success with setting up PayPal IPN on my website to manage subscription payments. I'm currently at the point where I have the payment set up in PayPal fine, and sending a completed payment from PayPal sandbox to my IPN works great and sets the MySQL row to is_paid to Yes instead of No, which then in turn allows the user to log in.

I am wondering now, how the IPN will let me know when the user's subscription payment fails or they cancel (all those bad and nasty things that happen in the real world!)? I'll want the IPN to send an email to the admin em

<?php
// tell PHP to log errors to ipn_errors.log in this directory
ini_set('log_errors', true);
ini_set('error_log', dirname(__FILE__).'/ipn_errors.log');

// intantiate the IPN listener
include('ipnlistener.php');
$listener = new IpnListener();

// tell the IPN listener to use the PayPal test sandbox
$listener->use_sandbox = true;

// try to process the IPN POST
try {
    $listener->requirePostMethod();
    $verified = $listener->processIpn();
} catch (Exception $e) {
    error_log($e->getMessage());
    exit(0);
}

// TODO: Handle IPN Response here

if ($verified) {

    $errmsg = '';   // stores errors from fraud checks

    // 1. Make sure the payment status is "Completed" 
    if ($_POST['payment_status'] != 'Completed') { 
        // simply ignore any IPN that is not completed
        exit(0); 
    }

    // 2. Make sure seller email matches your primary account email.
    if ($_POST['receiver_email'] != 'EMAILHERE') {
        $errmsg .= "'receiver_email' does not match: ";
        $errmsg .= $_POST['receiver_email']."\n";
    }

    // 3. Make sure the amount(s) paid match
    if ($_POST['mc_gross'] != '3.99') {
        $errmsg .= "'mc_gross' does not match: ";
        $errmsg .= $_POST['mc_gross']."\n";
    }

    // 4. Make sure the currency code matches
    if ($_POST['mc_currency'] != 'GBP') {
        $errmsg .= "'mc_currency' does not match: ";
        $errmsg .= $_POST['mc_currency']."\n";
    }

    // 5. Ensure the transaction is not a duplicate.
    mysql_connect('', '', '') or exit(0);
    mysql_select_db('') or exit(0);

    $txn_id = mysql_real_escape_string($_POST['txn_id']);
    $sql = "SELECT COUNT(*) FROM payments WHERE txn_id = '$txn_id'";
    $r = mysql_query($sql);

    if (!$r) {
        error_log(mysql_error());
        exit(0);
    }

    $exists = mysql_result($r, 0);
    mysql_free_result($r);

    if ($exists) {
        $errmsg .= "'txn_id' has already been processed: ".$_POST['txn_id']."\n";
    }

    if (!empty($errmsg)) {

        // manually investigate errors from the fraud checking
        $body = "IPN failed fraud checks: \n$errmsg\n\n";
        $body .= $listener->getTextReport();
        mail('EMAILHERE', 'PayPal IPN Fraud Warning', $body);

    } else {

    // add this order to a table of completed orders
    $payer_email = mysql_real_escape_string($_POST['payer_email']);
    $mc_gross = mysql_real_escape_string($_POST['mc_gross']);
    $sql = "INSERT INTO payments VALUES 
            (NULL, '$txn_id', '$payer_email', $mc_gross)";

    if (!mysql_query($sql)) {
        error_log(mysql_error());
        exit(0);
    }

    // sends an email to the user to confirm subscription
    $websitepath="http://www.gaymate.co.uk";
    $message='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
        <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>gaymate.co.uk</title>

        <style type="text/css">

        p {
            font-family: Arial;
            font-size: 12px;
            padding: 0 20px 0 20px; }

        .boldTitle {
            font-size: 13px;
            font-weight: bold; }

        .headerTitle {
            font-size: 16px;
            font-weight: bold; }

        .divider2 {
            padding: 0 20px 0 20px; }

        </style>

        </head>

        <body>
        <table width="500" border="0" cellspacing="0" cellpadding="0">
          <tr>
            <td>
            <a href="http://www.gaymate.co.uk/"><img src="http://www.gaymate.co.uk/images/email-header.jpg"></a>
            <img class="divider2" src="'.$websitepath.'/images/email/email-divider2.gif" alt="email-divider2" width="460" height="4" />
        <p>We have recieved confirmation from PayPal that you have completed payment and we are pleased to tell you that your account will be live on our site as soon as it has been approved by one of the moderators.</br></br>The Admin Team @ GayMate.co.uk</p>
       <img src="'.$websitepath.'/images/email/email-divider.gif" alt="email-divider" width="500" height="10" />
    </td>
  </tr>
</table>
<p>&nbsp;</p>
</body>
</html>
          ';


    $to = filter_var($_POST['payer_email'], FILTER_SANITIZE_EMAIL);
    $subject = "GayMate.co.uk Subscription Set-Up Completed";
    $header = "MIME-Version: 1.0\r\n";
    $header .= "From: EMAILHERE\r\n";
    $header .= "Reply-To: EMAILHERE\r\n";
    $header .= "Content-type: text/html; charset=iso-8859-1\r\n";
    mail($to, $subject, $message, $header);  
    }
    $sql = "UPDATE member SET is_paid='Yes' WHERE email='$to'";

    if (!mysql_query($sql)) {
        error_log(mysql_error());
        exit(0);
    }

} else {
    // manually investigate the invalid IPN
    mail('EMAILHERE', 'Invalid IPN', $listener->getTextReport());
}


?>

Upvotes: 1

Views: 946

Answers (2)

Danilo Kobold
Danilo Kobold

Reputation: 2581

Add those to your code and change the // email code // comment to your email code and it will work fine.

Before:

if ($_POST['payment_status'] != 'Completed') { 

Add:

// denied payment
if ($_POST['payment_status'] == 'Denied') { 
// email code
exit(0);
}

// failed subscription payment
if ($_POST['txn_type'] == 'subscr_failed') { 
// email code
exit(0);
}

// canceled subscription
if ($_POST['txn_type'] == 'subscr_cancel') { 
// email code
exit(0);
}

and just create the necessary for sending the email inside the comment.

Upvotes: 1

KaeruCT
KaeruCT

Reputation: 1645

You need to check the value of $_POST['txn_type'] in order to know what the notification is about.

From PayPal's documentation: https://www.paypal.com/cgi-bin/webscr?cmd=p/acc/ipn-subscriptions-outside

I believe you are interested in subscr_eot and subscr_failed.

Some extra information that might help you:

  • subscr_cancel is sent as soon as the user cancels their subscription.
  • subscr_eot is send once the subscription is due and they payment did not go through.

Once the user cancels their subscription, PayPal will send you subscr_cancel, and it will then send subscr_eot when their next payment was due.

You might also want to read this related question: Subscriptions with Paypal IPN

Upvotes: 1

Related Questions