如何正确读取PayPal IPN回传变量?解决custom变量异常问题
问题:无法正确读取PayPal IPN的custom变量
我已为此困扰数日,希望读取PayPal IPN系统传递的custom变量。多数资料显示使用$custom = $_POST['custom'];即可,但实际回传数据不符合预期。表单中custom变量包含动态值与固定值,我在ipn.php中用explode拆分,但不确定是否需复用PaypalIPN.php中的解码逻辑。我曾尝试Webhooks但不可靠,沙箱凭证无法使用,目前在生产环境测试,希望尽快解决正确读取变量的问题。
更新:已将$vars[]修正为$vars。
相关代码
ipn.php
<?php ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL); $servername = "localhost"; $username = "xxxxxxxx"; $password = "xxxxxxxxx"; $db = "xxxxxxxx"; // Create connection $conn = new mysqli($servername, $username, $password,$db); // Check connection if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } $replyTO = "nexxiom@gmail.com"; $senderName = "POWERMAILER IPN"; $timestamp = time(); $headers = "MIME-Version: 1.0" . "\n"; $headers .= "Content-type:text/html;charset=UTF-8" . "\n"; $headers .= 'From: <'.$replyTO.'>'.$senderName.'' . "\n" . 'Reply-To: '.$replyTO.'' . "\n" . 'X-Mailer: PHP/' . phpversion(); require('PaypalIPN.php'); use PaypalIPN; $ipn = new PaypalIPN(); // Use the sandbox endpoint during testing. //$ipn->useSandbox(); $verified = $ipn->verifyIPN(); if ($verified) { /* * Process IPN */ $custom = $_POST['custom']; $vars = explode(",",$custom); $uid = $vars[0]; $sid = $vars[1]; $newExpiry = $timestamp+2592000; $stmt = $conn->prepare('UPDATE users SET subscription_id = $sid, subscription_expiry = $newExpiry WHERE id = $uid'); $stmt->bind_param('i', $uid); $stmt->bind_param('i', $sid); $stmt->bind_param('i', $newExpiry); $stmt->execute(); $result = $stmt->get_result(); if ($result === TRUE) { mail($replyTO,"POWER MAILER SUBSCRIPTION","New Subscriber: IPN SUCCESS :: UID=".$uid." SID=".$sid." NEWEXP=".$newExpiry."",$headers); } else { mail($replyTO,"POWER MAILER SUBSCRIPTION","New Subscriber: IPN FAILED :: UID=".$uid." SID=".$sid." NEWEXP=".$newExpiry."",$headers); } $conn->close(); } // Reply with an empty 200 response to indicate to paypal the IPN was received correctly. header("HTTP/1.1 200 OK"); ?>
PaypalIPN.php(验证脚本)
<?php class PaypalIPN { /** @var bool Indicates if the sandbox endpoint is used. */ private $use_sandbox = false; /** @var bool Indicates if the local certificates are used. */ private $use_local_certs = true; /** Production Postback URL */ const VERIFY_URI = 'https://ipnpb.paypal.com/cgi-bin/webscr'; /** Sandbox Postback URL */ const SANDBOX_VERIFY_URI = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr'; /** Response from PayPal indicating validation was successful */ const VALID = 'VERIFIED'; /** Response from PayPal indicating validation failed */ const INVALID = 'INVALID'; /** * Sets the IPN verification to sandbox mode (for use when testing, * should not be enabled in production). * @return void */ public function useSandbox() { $this->use_sandbox = true; } /** * Sets curl to use php curl's built in certs (may be required in some * environments). * @return void */ public function usePHPCerts() { $this->use_local_certs = false; } /** * Determine endpoint to post the verification data to. * * @return string */ public function getPaypalUri() { if ($this->use_sandbox) { return self::SANDBOX_VERIFY_URI; } else { return self::VERIFY_URI; } } /** * Verification Function * Sends the incoming post data back to PayPal using the cURL library. * * @return bool * @throws Exception */ public function verifyIPN() { if ( ! count($_POST)) { throw new Exception("Missing POST Data"); } $raw_post_data = file_get_contents('php://input'); $raw_post_array = explode('&', $raw_post_data); $myPost = array(); foreach ($raw_post_array as $keyval) { $keyval = explode('=', $keyval); if (count($keyval) == 2) { // Since we do not want the plus in the datetime string to be encoded to a space, we manually encode it. if ($keyval[0] === 'payment_date') { if (substr_count($keyval[1], '+') === 1) { $keyval[1] = str_replace('+', '%2B', $keyval[1]); } } $myPost[$keyval[0]] = urldecode($keyval[1]); } } // Build the body of the verification post request, adding the _notify-validate command. $req = 'cmd=_notify-validate'; $get_magic_quotes_exists = false; if (function_exists('get_magic_quotes_gpc')) { $get_magic_quotes_exists = true; } foreach ($myPost as $key => $value) { if ($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) { $value = urlencode(stripslashes($value)); } else { $value = urlencode($value); } $req .= "&$key=$value"; } // Post the data back to PayPal, using curl. Throw exceptions if errors occur. $ch = curl_init($this->getPaypalUri()); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_SSLVERSION, 6); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // This is often required if the server is missing a global cert bundle, or is using an outdated one. if ($this->use_local_certs) { curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . "/cert/cacert.pem"); } curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'User-Agent: PHP-IPN-Verification-Script', 'Connection: Close', )); $res = curl_exec($ch); if ( ! ($res)) { $errno = curl_errno($ch); $errstr = curl_error($ch); curl_close($ch); throw new Exception("cURL error: [$errno] $errstr"); } $info = curl_getinfo($ch); $http_code = $info['http_code']; if ($http_code != 200) { throw new Exception("PayPal responded with http code $http_code"); } curl_close($ch); // Check if PayPal verifies the IPN data, and if so, return true. if ($res == self::VALID) { return true; } else { return false; } } } ?>
PayPal支付按钮表单
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top"> <input type="hidden" name="custom" value="<?php echo $uid;?>,4"/> <input type="hidden" name="cmd" value="_s-xclick" /> <input type="hidden" name="hosted_button_id" value="HU6L2WHVBPXWU" /> <input type="hidden" name="currency_code" value="CAD" /> <input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" title="PayPal - The safer, easier way to pay online!" alt="Buy Now" /> </form>
内容的提问来源于stack exchange,提问作者Brent Doucette
相关产品推荐
相关产品推荐

