如何读取 Paypal IPN 回发变量

问题描述 投票:0回答:1

我已经为此苦苦挣扎了几天。 我想读取通过 IPN 系统传递的自定义变量。 大多数人说 $custom = $_POST['custom'];就是你如何做。 然而,回发的数据并不是预期的数据。

这是代码:

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 = "[email protected]";
$senderName = "POWERMAILER IPN";
$timestamp = time();
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type:text/html;charset=UTF-8" . "\r\n";
$headers .= 'From: <'.$replyTO.'>'.$senderName.'' . "\r\n" .
'Reply-To: '.$replyTO.'' . "\r\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
     * A list of variables is available here:
     * https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/
     */


    $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>

您可以在表单中看到我有一个自定义变量,它接受已发布的变量和带有设置值的逗号。 我在 ipn.php 上爆炸了 我还看到验证 php (PaypalIPN.php) 上的代码对回发变量进行了解码。但我不太确定是否可以抓住该循环并在 ipn.php 上再次使用它

有人可以阐明如何正确读取变量吗? 预先感谢!

我尝试过 Webhooks(不可靠) 我尝试过使用沙箱帐户,但沙箱凭据永远无法工作,因此我正在实时环境中对此进行测试,因此尽早获得正确结果会有所帮助。 我做的下一个测试将向我发送一封包含输出的电子邮件。但我想要代码 在明天早上的考试之前做好更多准备。

SQL注入更新 有人可以看一下并在评论中告诉我这是否是正确的用法吗?

$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();

我还将 $vars[] 更新为 $vars

php paypal-ipn
1个回答
0
投票

我刚刚读过

$_POST['custom']
。就是这么简单。不过,请务必进行回发验证,以确保传入的 POST 确实来自 PayPal。

请注意,某些事件可能在没有自定义变量的情况下出现。但这些都是订阅或拒绝等事情的后续。然而,对于客户的表单发布,他们肯定会有自定义变量。现在,我注意到您使用了“立即购买”按钮策略,但这不适用于订阅。他们针对该用例有另一种表单和按钮策略。现在,如果您在自己的代码中进行自己的“订阅”,那就是另一回事了。

您可能还想检查可以和不能发布到该变量中的不同字符串字符,以及该变量可以有多长。它可能会在运输过程中被损坏。

© www.soinside.com 2019 - 2024. All rights reserved.