Paypal IPN取消会员资格PHP

So the code that I've got for when a user purchases membership works perfectly. However I'm unsure how to code if for when the user cancels. What fields do papal throw at you when the user cancels through them?

I understand I'm supposed to use subscr_cancelled but am unsure the correct psuedocode and logic behind the cancellation.

For example:

  • What is the payment status when the user cancels?
  • Do I just ignore payment status?

Here's my code thus far, its a little clunky as i've been testing a lot:

if (strcmp ($res, "VERIFIED") == 0) {
    // check whether the payment_status is Completed
    // check that txn_id has not been previously processed
    // check that receiver_email is your PayPal email
    // check that payment_amount/payment_currency are correct
    // process payment and mark item as paid.
    // assign posted variables to local variables

    $item_name = $_POST['item_name'];
    $item_number = $_POST['item_number'];
    $txn_type = $_POST['txn_type'];
    $payment_status = $_POST['payment_status'];
    $payment_amount = $_POST['mc_gross'];
    $payment_currency = $_POST['mc_currency'];
    $txn_id = $_POST['txn_id'];
    $receiver_email = $_POST['receiver_email'];
    $payer_email = $_POST['payer_email'];
    $id = $_POST['custom'];
    $make_premium =1;
    $make_loser=0;


        if($payment_status=="Completed"){
        $user_id_check = $mysqli->query("SELECT `username` FROM `users` WHERE `ID` ='$id'");
        if($user_id_check->num_rows > 0){
            $txn_id_check = $mysqli->query("SELECT `transaction_id` FROM `payment` WHERE `transaction_id`='$txn_id'");
            if($txn_id_check->num_rows != 1) {  
                        $query = "INSERT INTO `payment` (`transaction_id`, `payment_status`, `users_id`, `txn_type`) VALUES(?, ?, ?, ?)";
                        $statement = $mysqli->prepare($query);
                        $statement->bind_param('ssis',$txn_id, $payment_status, $id, $txn_type);
                        if($statement->execute()){
                            if($txn_type =="subscr_signup"){
                                $update_user_to_premium =("UPDATE `users` SET `is_member` =? WHERE `ID` =?");
                                $stmt =$mysqli->prepare($update_user_to_premium);
                                $stmt->bind_param('ii',$make_premium,$id);
                                $stmt->execute();
                            }
                        }else{
                        die('Error : ('. $mysqli->errno .') '. $mysqli->error);
                        }
                        $statement->close();
               }
            }
        }
    }
    if($txn_id_check->num_rows == 1){
        if($txn_type=="subscr_cancel"){
            $update_user_to_loser =("UPDATE `users` SET `is_member` =? WHERE `ID` =?");
            $stmt =$mysqli->prepare($update_user_to_loser);
            $stmt->bind_param('ii',$make_loser,$id);
            $stmt->execute();
        }
    {
    if(DEBUG == true) {
        error_log(date('[Y-m-d H:i e] '). "Verified IPN: $req ". PHP_EOL, 3, LOG_FILE);
    }
} else if (strcmp ($res, "INVALID") == 0) {
    // log for manual investigation
    // Add business logic here which deals with invalid IPN messages
    if(DEBUG == true) {
        error_log(date('[Y-m-d H:i e] '). "Invalid IPN: $req" . PHP_EOL, 3, LOG_FILE);
    }
}

Should I be using something like this

switch ($_POST['txn_type']) {   
 case 'subscr_signup':
        break;

    case 'subscr_eot':
       //subscription end of term
        break;

    case 'subscr_cancel':
        //subscription canceled
        break;

EDIT:

if (strcmp ($res, "VERIFIED") == 0) {
    // check whether the payment_status is Completed
    // check that txn_id has not been previously processed
    // check that receiver_email is your PayPal email
    // check that payment_amount/payment_currency are correct
    // process payment and mark item as paid.
    // assign posted variables to local variables

    $item_name = $_POST['item_name'];
    $item_number = $_POST['item_number'];
    $txn_type = $_POST['txn_type'];
    $payment_status = $_POST['payment_status'];
    $payment_amount = $_POST['mc_gross'];
    $payment_currency = $_POST['mc_currency'];
    $txn_id = $_POST['txn_id'];
    $receiver_email = $_POST['receiver_email'];
    $payer_email = $_POST['payer_email'];
    $id = $_POST['custom'];
    $subscr_id = $_POST['subscr_id'];
    $make_premium =1;
    $make_loser=0;


        if($payment_status=="Completed"){
        $user_id_check = $mysqli->query("SELECT `username` FROM `users` WHERE `ID` ='$id'");
        if($user_id_check->num_rows > 0){
            $txn_id_check = $mysqli->query("SELECT `transaction_id` FROM `payment` WHERE `transaction_id`='$txn_id'");
            if($txn_id_check->num_rows != 1) {  
                        $query = "INSERT INTO `payment` (`transaction_id`, `payment_status`, `users_id`, `txn_type`, `subscr_id`) VALUES(?, ?, ?, ?, ?)";
                        $statement = $mysqli->prepare($query);
                        $statement->bind_param('ssiss',$txn_id, $payment_status, $id, $txn_type, $subscr_id);
                        if($statement->execute()){
                            if($txn_type =="subscr_signup"){
                                $update_user_to_premium =("UPDATE `users` SET `is_member` =? WHERE `ID` =?");
                                $stmt =$mysqli->prepare($update_user_to_premium);
                                $stmt->bind_param('ii',$make_premium,$id);
                                $stmt->execute();
                            }
                        }else{
                        die('Error : ('. $mysqli->errno .') '. $mysqli->error);
                        }
                        $statement->close();
               }
            }
        }
    }

        if($txn_type=="subscr_cancel"){
            // get user id from row with subscription id 
            $get_user_id = $mysqli->("SELECT `users_id` FROM `payment` WHERE `subscr_id`='$subscr_id'");
            $row = $get_user_id->fetch_assoc();
            $users_id = $row[`users_id`];
            $update_user_to_loser =("UPDATE `users` SET `is_member` =? WHERE `ID` =?");
            $stmt =$mysqli->prepare($update_user_to_loser);
            $stmt->bind_param('ii',$make_loser,$users_id);
            $stmt->execute();
        }
    {
    if(DEBUG == true) {
        error_log(date('[Y-m-d H:i e] '). "Verified IPN: $req ". PHP_EOL, 3, LOG_FILE);
    }
} else if (strcmp ($res, "INVALID") == 0) {
    // log for manual investigation
    // Add business logic here which deals with invalid IPN messages
    if(DEBUG == true) {
        error_log(date('[Y-m-d H:i e] '). "Invalid IPN: $req" . PHP_EOL, 3, LOG_FILE);
    }
}
?>

If a profile is canceled then there is no payment taking place. That's a different type of transaction. There is no payment, so there is no payment status, so you won't get that parameter in that sort of an IPN.

You can easily test this in the sandbox. You just need to create a seller account and a buyer account, and configure IPN in your seller account to hit your listener. Then create a subscription button from the seller account, sign up from the buyer account, and then cancel it. That will trigger IPNs for each step so you can see what to expect and adjust your IPN listener accordingly.

Here is an example of an IPN for a subscr_cancel transaction.

Array
(
    [amount3] => 4.99
    [address_status] => confirmed
    [recur_times] => 2
    [subscr_date] => 15:51:33 Jan 19, 2015 PST
    [payer_id] => YW66KXBKJRRES
    [address_street] => 123 Test Ave
    [mc_amount3] => 4.99
    [charset] => windows-1252
    [address_zip] => 64030
    [first_name] => Tester
    [reattempt] => 1
    [address_country_code] => US
    [address_name] => Testers, LLC
    [notify_version] => 3.8
    [subscr_id] => S-6YS75493RP123324L
    [payer_status] => verified
    [business] => sandbo_1215254764_biz@angelleye.com
    [address_country] => United States
    [address_city] => Grandview
    [verify_sign] => AI7Wj0s667jdpY.UclGpjUpSpsZNAJzn.UcYbCVhXVG5fO05tyBo36EL
    [payer_email] => drew@angelleye.com
    [payer_business_name] => Testers, LLC
    [last_name] => Testerson
    [address_state] => MO
    [receiver_email] => sandbo_1215254764_biz@angelleye.com
    [recurring] => 1
    [txn_type] => subscr_cancel
    [item_name] => Test Subscription
    [mc_currency] => USD
    [item_number] => TEST-123
    [residence_country] => US
    [test_ipn] => 1
    [period3] => 1 M
    [ipn_track_id] => f0f2f2be88fd
)