Paypal SandBox IPN始终返回INVALID

osh*_*nen 10 php paypal paypal-sandbox paypal-ipn

正如下面答案中的一条评论中提到的,我尝试了本教程.所以现在我有以下内容:


ipn.php文件:

<?php

    $ipn_post_data = $_POST;

    $url = 'https://www.sandbox.paypal.com/cgi-bin/webscr';

    // Set up request to PayPal
    $request = curl_init();
    curl_setopt_array($request, array
    (
        CURLOPT_URL => $url,
        CURLOPT_POST => TRUE,
        CURLOPT_POSTFIELDS => http_build_query(array('cmd' => '_notify-validate') + $ipn_post_data),
        CURLOPT_RETURNTRANSFER => TRUE,
        CURLOPT_HEADER => FALSE,
        CURLOPT_SSL_VERIFYPEER => TRUE,
        CURLOPT_CAINFO => 'cacert.pem',
    ));

    // Execute request and get response and status code
    $response = curl_exec($request);
    $status   = curl_getinfo($request, CURLINFO_HTTP_CODE);

    // Close connection
    curl_close($request);

    if($status == 200 && $response == 'VERIFIED')
    {
        $subject = "valid";
        $message = "good";
    }
    else
    {
        $subject = "invalid";
        $message = "bad";
    }

    $to = "oshirowanen@mail.com";
    $from = "me@desktop.com";

    $header  = 'MIME-Version: 1.0' . "\r\n";
    $header .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
    $header .= 'To: Oshirowanen <oshirowanen@mail.com>' . "\r\n";
    $header .= 'From: Me <me@desktop.com>' . "\r\n";

    mail($to,$subject,$message,$header);

?>
Run Code Online (Sandbox Code Playgroud)

收到的电子邮件:

Subject "invalid"
Message "bad"
Run Code Online (Sandbox Code Playgroud)

Ste*_*rex 14

编辑:

现在我可以看到你输出的数组,尝试替换它以摆脱PHP数组错误:

foreach ($_POST as $key => $value) {
    if (!is_array($value)) {
        $value = urlencode(stripslashes($value));
        $req .= "&$key=$value";
    }
    else if (is_array($value)) {
        $paymentArray = explode(' ', $value[0]);
        $paymentCurrency = urlencode(stripslashes($paymentArray[0]));
        $paymentGross = urlencode(stripslashes($paymentArray[1]));
        $req .= '&mc_currency=' . $paymentCurrency . '&mc_gross=' . $paymentGross;
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是完整编辑的代码:

// read the post from PayPal system and add 'cmd'
$req = 'cmd=' . urlencode('_notify-validate');

foreach ($_POST as $key => $value) {
    if (!is_array($value)) {
        $value = urlencode(stripslashes($value));
        $req .= "&$key=$value";
    }
    else if (is_array($value)) {
        $paymentArray = explode(' ', $value[0]);
        $paymentCurrency = urlencode(stripslashes($paymentArray[0]);
        $paymentGross = urlencode(stripslashes($paymentArray[1]);
        $req .= '&mc_currency=' . $paymentCurrency . '&mc_gross=' . $paymentGross;
    }
}

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://www.paypal.com/cgi-bin/webscr');
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Host: www.paypal.com'));
$res = curl_exec($ch);
curl_close($ch);


// assign posted variables to local variables
$item_name = $_POST['item_name'];
$item_number = $_POST['item_number'];
$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'];


if (strcmp ($res, "VERIFIED") == 0) {
    // check the payment_status is Completed
    // check that txn_id has not been previously processed
    // check that receiver_email is your Primary PayPal email
    // check that payment_amount/payment_currency are correct
    // process payment
}
else if (strcmp ($res, "INVALID") == 0) {
    // log for manual investigation
}
Run Code Online (Sandbox Code Playgroud)

看看这个!

编辑:查看PayPal故障排除提示:

https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_admin_IPNTesting


小智 6

问题是您没有检查HTTP响应代码,因此您将"无效主机标头"解释为PayPal响应,而它是Web服务器响应(对于状态代码400).
如果您查看PayPal文档,有一个PHP示例与您的代码非常相似,因为它使用"fsockopen","fputs"和"fgets"函数与PayPal服务器进行通信.
但是如果你仔细看看"fsockopen"调用后的评论,你可以阅读:

// Process validation from PayPal 
// TODO: This sample does not test the HTTP response code. All 
// HTTP response codes must be handled or you should use an HTTP 
// library, such as cUrl
Run Code Online (Sandbox Code Playgroud)

这是你的问题:在解析响应体之前,你没有检查HTTP响应代码是否为200(OK).
此外,使用"strtolower"功能是不正确的,因为来自PayPal服务器的实际响应始终是大写的,如上面引用的示例所示.
即使PayPal示例使用"fsockopen"方法,我认为使用PHP cURL库来实现您的IPN侦听器应该更好.
还看看以下答案:

但是,如果您真的想使用"fsockopen"函数,则应始终在POST请求中指定"Host"头字段,如以下代码片段所示(摘自PHP手册):

<?php
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)<br />\n";
} else {
    $out = "GET / HTTP/1.1\r\n";
    $out .= "Host: www.example.com\r\n";
    $out .= "Connection: Close\r\n\r\n";
    fwrite($fp, $out);
    while (!feof($fp)) {
        echo fgets($fp, 128);
    }
    fclose($fp);
}
?>
Run Code Online (Sandbox Code Playgroud)

UPDATE

这是递归stripslashes/urlencoding的简单函数:

<html>
<body>
<pre>
<?

$post = Array (
  "transaction" => Array("USD 20.00"),
  "payment_request_date" => "Sun Aug '05 08:49:20 PDT 2012",
  "return_url" => "http://000.000.000.000/success.php"
);

echo "before myUrlencode...\n";
print_r($post);

function myUrlencode($post) {
  foreach ($post as $key => $val) {
    if (is_array($val)) {
      $post[$key] = myUrlencode($val);
    } else {
      $post[$key] = urlencode(stripslashes($val));
    }
  }
  return($post);
}

echo "\nafter myUrlencode...\n";
print_r(myUrlencode($post));

?>
</pre>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)


osh*_*nen 2

  1. 使用基本示例代码4b让它工作,

  2. 从基本示例代码中清除$ipnNotificationUrl = "";,因为我在其中添加了自己的值,

  3. 在沙箱中创建了卖家帐户而不是商业专业帐户,

  4. 设置卖家账户启用ipn url,

  5. 使用以下 PHP 5.2示例代码作为 iPN 监听器

  6. 将这两行添加到监听器中,如下所述这两行如下所示:

  7. 从这里将证书下载cacert.pem到我的服务器并将其放在与 ipn 侦听器相同的目录中:

第 6 点提到的 2 行:

CURLOPT_SSL_VERIFYPEER => TRUE,
CURLOPT_CAINFO => 'cacert.pem',
Run Code Online (Sandbox Code Playgroud)

我不知道为什么沙盒商业专业帐户不允许我设置 iPN url,但卖家帐户可以。