3

最近の変更に合わせて、PayPal IPN スクリプトの更新に取り組んでいます。これはPayPalによる説明の一部です...

2013 年 2 月 1 日より前に必要なアクション HTTP 1.1 を使用するように IPN および/または PDT スクリプトを更新し、IPN および PDT に「Host: www.paypal.com」および「Connection: close」HTTP ヘッダーを含める必要があります。スクリプト。

私たちはそれを行いましたが、IPN は失敗しました。PayPal Merchant Technical Service から、SLL 接続に移行するよう依頼されました。以前は、PayPal への接続は ... に基づいていました。

fsockopen ('www.paypal.com', 80, $errno, $errstr, 30)

今は...

fsockopen ('ssl://ipnpb.paypal.com', 443, $errno, $errstr, 30)

これを機能させるには、ホスト構成で SSL の問題を解決する必要がありましたが、現在は接続を確立しています。ただし、IPN では、「VERIFIED」通知を受け取るために PayPal に返送する必要があります。この時点で、スクリプトは確認済みの支払いに基づいてローカル処理を実行できます。

これが失敗するところです。

サンプル PayPal スクリプトの行は次のとおりです。

if (!$fp) {
    // HTTP ERROR

} else {
    fputs ($fp, $header . $req);
    while (!feof($fp)) {
        $res = fgets ($fp, 1024);

        if (strcmp (trim($res), "VERIFIED") == 0) {  ... rest of script

しかし、応答は空白になります。各段階で $res の値をメールで送信する診断を挿入しました。古いスクリプトでこれを行うと、「VERIFIED」値が正常に返されます。いくつかのサイトの古いスクリプトは何年も安定しています。2 つの異なるサーバー上の 2 つの異なるサイトでこれらの新しい更新を試してみましたが、結果は同じです。

Apache ログを見ると、次のエラーが表示されます。

PHP 警告: fgets() [function.fgets]: SSL: 145 行目の /home/[sitename]/public_html/[IPN scriptname].php のピアによって接続がリセットされました

そのため、PayPal は Verified 応答を送信せずに接続をシャットダウンしたようです。ただし、PayPal サポートは、接続が最初に開かれているため、これが問題であることを否定しています。

これを修正するために数日を費やしました。私にはまだ 2 月 1 日の期限があり、それ以降は私の古いスクリプトは機能しない可能性があると PayPal から言われていますが、新しいスクリプトも機能しません。

他の誰かがこれについて経験がありますか?

4

4 に答える 4

1

ついに答えが見つかりました! Paypal IPN スクリプト、feof と fgets の問題

削除して追加するようwhile(!feof($fp) ... に変更し、ペイパルが接続を確実に閉じるようにします。$res = stream_get_contents($fp, 1024);$header .= "Conection: Close"

于 2014-02-21T23:16:13.713 に答える
0

更新: 2016 年 1 月 7 日 tls://www.sandbox.paypal.com では以下が非常にうまく機能することに気付きましたが、tls ://www.paypal.com にライブ接続すると接続が拒否されます! (動作しません) 問題はヘッダー、サンドボックスにあり、実稼働レベルのライブ ペイパルには別のヘッダーが必要であることがわかりました。これはバグですが、本番レベルとサンドボックスの両方で機能させるには、それぞれ次のヘッダーを使用してください。

プロダクション レベル (ライブ PayPal ヘッダー):

  $header  = "POST /cgi-bin/webscr HTTP/1.1\r\n"; 
  $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
  $header .= "Content-Length: " . strlen($req) . "\r\n\r\n";

サンドボックス PayPal ヘッダー:

$header  = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Host: www.paypal.com\r\n";
$header .= "Accept: */*\r\n";
$header .= "Connection: Close\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "\r\n";

* 以下のコードは同じで、ヘッダーをそれぞれ置き換えるだけで問題なく動作します。* コードの残りの部分 (および回答) は次のとおりです。

2016 年 1 月 5 日に機能するように、あちこちのすべての回答を確認しました。すべてに良い点がありましたが、全体像では機能しませんでした。

まず、実際に動作する完全なコードを次に示します。

<?php

// =========================================================================
// PayPal Official PHP Codes and Tutorial:
// https://developer.paypal.com/webapps/developer/docs/classic/ipn/gs_IPN/
// =========================================================================

// Send an empty HTTP 200 OK response to acknowledge receipt of the notification 
header('HTTP/1.1 200 OK');

// Assign payment notification values 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'];

// Build the required acknowledgement message out of the notification just received
$req = 'cmd=_notify-validate';               // Add 'cmd=_notify-validate' to beginning of the acknowledgement

foreach ($_POST as $key => $value) {         
    // Loop through the notification NV pairs
    $value = urlencode(stripslashes($value));  // Encode these values
    $req  .= "&$key=$value";                   // Add the NV pairs to the acknowledgement
}


// Set up the acknowledgement request headers
// HTTP POST request
$header  = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Host: www.sanbox.paypal.com\r\n";
$header .= "Accept: */*\r\n";
$header .= "Connection: Close\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "\r\n";

// Open a socket for the acknowledgement request
$fp = fsockopen('tls://www.sandbox.paypal.com', 443, $errno, $errstr, 30);

// Send the HTTP POST request back to PayPal for validation
fputs($fp, $header . $req);

// Log the transaction:
file_put_contents("paypal_post.txt",  date('Y-m-d H:i:s')."\n".file_get_contents("php://input")."\n\n", FILE_APPEND);

// While not EOF
while (!feof($fp)) {
    // Get the acknowledgement response
    // $res = fgets($fp, 1024);  
    $res = stream_get_contents($fp, 1024);
    $responses = explode("\r\n", $res);
    foreach ($responses as $response) {
        if (strcmp ($response, "VERIFIED") == 0) {
            // Response contains VERIFIED - process notification

            // Authentication protocol is complete - OK to process notification contents

            // Possible processing steps for a payment include the following:

            // Check that 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 ($response, "INVALID") == 0) {
            // Response contains INVALID - reject notification
            // Authentication protocol is complete - begin error handling

        }
    }
}
// Close the file
fclose($fp);
?>

OK、これで PayPal IPNをリッスンし、再コンパイルして検証のために PayPalに送り返し、ヘッダーを受け取り、ヘッダーを 1行ずつ処理してVERIFIED検証を見つけるように機能するコードができました。

これは、動作状態で PayPal オールインワン パッケージによって提供されるはずですが、チュートリアルには非常に重要な部分が欠けていて、私やこのスレッドの多くの人にとってはうまくいきませんでした。

それでは、それを機能させる重要な部分は何ですか: まず、paypal が提供するヘッダーが機能しませんでした。@jp_eagle のヘッダーは完全に機能することがわかりました。

$res = fgets($fp, 1024); のペイパルは間違っていました。同じように...

ただし、 $res = stream_get_contents($fp, 2048); は必要ありません。@jp_eagle が提案したように、 $res = stream_get_contents($fp, 1024); 大丈夫です。

while (!feof($fp)) {} ループが機能するようにそこにとどまる必要があります! はい、 fgets() から stream_get_contents() に切り替えても、そこにとどまるはずです!

@richbai90 は、それを削除するという提案は間違っていました。他の方法を試してもうまくいきません...

VALIDATION を取得するための最も重要な部分は、次のループです。

    $res = stream_get_contents($fp, 1024);
    $responses = explode("\r\n", $res);
    foreach ($responses as $response) {}

ここで、各行で VALIDATION を探すことができます。

if (strcmp ($response, "VERIFIED") == 0) {}

また、何よりも前に、最初の完全な受信 POST リクエスト フォーム ペイパルをログに記録しました。

// トランザクションを記録します: file_put_contents("paypal_post.txt", date('Ymd H:i:s')."\n".file_get_contents("php://input")."\n\n", FILE_APPEND );

それでおしまい。ここにアクセスしてペイパルでログインし、動作するかどうかを確認してください: https://developer.paypal.com/developer/ipnSimulator/

たとえば、「カート チェックアウト」を選択する URL を指定し、テスト IPN を送信します。問題なく動作する場合は、www.sandbox.paypal.com から www.paypal.com への上記のペイパル URL から .sandbox を削除してください。

if-else ステートメントの VERIFIED セクションと INVALID セクションにデータベース アクションを入力すれば完了です。

于 2016-01-06T01:13:22.530 に答える