3 # this script does not use wfpl_main, so:
4 require_once(__DIR__.'/'.'config.php');
6 require_once(__DIR__.'/'.'inc/wfpl/template.php');
7 require_once(__DIR__.'/'.'inc/wfpl/format.php');
9 function paypal_ipn_main() {
10 // read the post from PayPal system and add 'cmd'
11 $req = 'cmd=_notify-validate';
12 $log = 'Received IPN:';
14 foreach ($_POST as $key => $value) {
15 $log .= "\n$key: $value";
16 $value = urlencode($value);
17 $req .= "&$key=$value";
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'] : '';
36 $ch = curl_init($GLOBALS['paypal_site'] . '/cgi-bin/webscr');
38 $status = 'curl_init failed';
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);
52 if ($curl_errno != 0) {
53 $status = 'curl fail: ' . $curl_errno;
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') {
61 } elseif ($res_word === 'INVALID') {
64 $log .= "\n\nCan't figure out PayPal verify reply:\n" . $res;
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,
82 'txn_type' => $txn_type,
83 'subscr_id' => $subscr_id,
84 'user_id' => $user_id,
88 db_insert_assoc('paypal_ipn', $row);
89 $row['id'] = $ipn_id = db_auto_id();
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\"");
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\"");
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\"");
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\"");
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;
123 db_update_assoc('paypal_ipn', $update);
125 paypal_ipn_main_debug($user, $old_date, $was_expired);
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";
137 $template_vars = ['details' => $message];
138 email_with_template(null, 'backend_debug', $template_vars);
141 # this file is accessed directly from the paypal IPN system
142 ini_set('display_errors', '0');
143 ini_set('log_errors', '1');