更新: 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 セクションにデータベース アクションを入力すれば完了です。