JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
don't overwrite .centerer vmargin
[wfpl-cms.git] / paypal_ipn.php
1 <?php
2
3 # this script does not use wfpl_main, so:
4 require_once(__DIR__.'/'.'config.php');
5
6 require_once(__DIR__.'/'.'inc/wfpl/template.php');
7 require_once(__DIR__.'/'.'inc/wfpl/format.php');
8
9 function paypal_ipn_main() {
10         // read the post from PayPal system and add 'cmd'
11         $req = 'cmd=_notify-validate';
12         $log = 'Received IPN:';
13
14         foreach ($_POST as $key => $value) {
15                 $log .= "\n$key: $value";
16                 $value = urlencode($value);
17                 $req .= "&$key=$value";
18         }
19
20         // assign posted variables to local variables
21         $item_name      = isset($_POST['item_name'])      ? $_POST['item_name']      : '';
22         $item_number    = isset($_POST['item_number'])    ? $_POST['item_number']    : '';
23         $payment_status = isset($_POST['payment_status']) ? $_POST['payment_status'] : '';
24         $mc_gross       = isset($_POST['mc_gross'])       ? $_POST['mc_gross']       : '';
25         $mc_currency    = isset($_POST['mc_currency'])    ? $_POST['mc_currency']    : '';
26         $txn_id         = isset($_POST['txn_id'])         ? $_POST['txn_id']         : '';
27         $receiver_email = isset($_POST['receiver_email']) ? $_POST['receiver_email'] : '';
28         $payer_email    = isset($_POST['payer_email'])    ? $_POST['payer_email']    : '';
29         $custom         = isset($_POST['custom'])         ? $_POST['custom']         : '';
30         $txn_type       = isset($_POST['txn_type'])       ? $_POST['txn_type']       : '';
31         $subscr_id      = isset($_POST['subscr_id'])      ? $_POST['subscr_id']      : '';
32         $needs_review = 1;
33
34         $status = 'unknown';
35
36         $ch = curl_init($GLOBALS['paypal_site'] . '/cgi-bin/webscr');
37         if ($ch == false) {
38                 $status = 'curl_init failed';
39         } else {
40                 curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
41                 curl_setopt($ch, CURLOPT_POST, 1);
42                 curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
43                 curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
44                 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
45                 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
46                 curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
47                 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
48                 curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
49                 $res = curl_exec($ch);
50                 $curl_errno = curl_errno($ch);
51                 curl_close($ch);
52                 if ($curl_errno != 0) {
53                         $status = 'curl fail: ' . $curl_errno;
54                 } else {
55                         // Split response headers and payload, a better way for strcmp
56                         $tokens = explode("\r\n\r\n", trim($res));
57                         $res = trim(end($tokens));
58                         $res_word = trim($tokens[count($tokens) - 1]);
59                         if ($res_word === 'VERIFIED') {
60                                 $status = 'verified';
61                         } elseif ($res_word === 'INVALID') {
62                                 $status = 'invalid';
63                         } else {
64                                 $log .= "\n\nCan't figure out PayPal verify reply:\n" . $res;
65                         }
66                 }
67         }
68
69         $row = [
70                 'txn_id' =>            $txn_id,
71                 'status' =>            $status,
72                 'custom' =>            $custom,
73                 'item_name' =>         $item_name,
74                 'item_number' =>       $item_number,
75                 'needs_review' =>      $needs_review,
76                 'payment_status' =>    $payment_status,
77                 'mc_gross' =>          $mc_gross,
78                 'mc_currency' =>       $mc_currency,
79                 'receiver_email' =>    $receiver_email,
80                 'payer_email' =>       $payer_email,
81                 'log' =>               $log,
82                 'txn_type' =>          $txn_type,
83                 'subscr_id' =>         $subscr_id,
84                 'user_id' =>           $user_id,
85                 'ipn_at' =>            time()
86         ];
87
88         db_insert_assoc('paypal_ipn', $row);
89         $row['id'] = $ipn_id = db_auto_id();
90
91         if($status !== 'verified') {    # it's really from PayPal
92                 paypal_ipn_main_debug("status is not \"verified\" but is \"$status\"");
93         } elseif ($txn_type !== 'subscr_payment' && $txn_type !== 'web_accept') {
94                 if ($txn_type !== 'subscr_signup' && $txn_type !== 'subscr_cancel' && $txn_type !== 'subscr_eot') {
95                         # subscr_cancel is sent when they cancel. After that:
96                         # subscr_eot is sent when their next payment would have been
97                         paypal_ipn_main_debug("txn_type is not \"subscr_payment\", \"subscr_signup\", \"subscr_cancel\", \"subscr_eot\" or \"web_accept\" but is \"$txn_type\"");
98                 }
99         } elseif ($payment_status !== 'Completed') { # payment has completed
100                 if ($payment_status !== 'Pending') {
101                         paypal_ipn_main_debug("payment_status is not \"Completed\" or \"Pending\", but is \"$payment_status\"");
102                 }
103         } elseif ($receiver_email !== $GLOBALS['paypal_email']) {
104                 paypal_ipn_main_debug("payment isn't to us ($GLOBALS[paypal_email]) but to \"$receiver_email\"");
105         } elseif ($mc_currency !== 'USD') {
106                 paypal_ipn_main_debug("Currency isn't \"USD\" but is \"$mc_currency\"");
107         } else {
108                 $custom_words = explode(' ', $custom);
109                 if (!isset($GLOBALS['payment_handlers'][$custom_words[0]])) {
110                         paypal_ipn_main_debug("\$custom's first word isn't in GLOBALS[payment_handlers]. \$custom: \"$custom\"");
111                 } else {
112                         $ret = file_run($GLOBALS['payment_handlers'][$custom_words[0]], $custom_words, $mc_gross, $row);
113                         if ($ret and is_array($ret) and isset($ret['success']) and $ret['success']) {
114                                 $update = ['processed' => '1'];
115                                 if (isset($ret['for_table_id']) and isset($ret['for_row_id'])) {
116                                         $tid = format_int_0((string)$ret['for_table_id']);
117                                         $rid = format_int_0((string)$ret['for_row_id']);
118                                         if ((int)$tid > 0 and (int)$rid > 0) {
119                                                 $update['for_table_id'] = $tid;
120                                                 $update['for_row_id'] = $rid;
121                                         }
122                                 }
123                                 db_update_assoc('paypal_ipn', $update);
124                         } else {
125                                 paypal_ipn_main_debug($user, $old_date, $was_expired);
126                         }
127                 }
128         }
129 }
130
131 function paypal_ipn_main_debug($message) {
132         $message = this_host() . ' paypal payment failure ' . $_POST['ipn_track_id'] . "\n\n" . $message;
133         $message .= "\n\nDump of all info received:\n";
134         foreach ($_POST as $key => $value) {
135                 $message .= "\t$key: $value\n";
136         }
137         $template_vars = ['details' => $message];
138         email_with_template(null, 'backend_debug', $template_vars);
139 }
140
141 # this file is accessed directly from the paypal IPN system
142 ini_set('display_errors', '0');
143 ini_set('log_errors', '1');
144 paypal_ipn_main();