wordpressでpaypalからのIPN通知を受信可能にするやり方
PHP PayPal IPNを利用
wordpressのマルチサイト構成でpaypal決済を統合する際のIPN回りについてエントリーしてみる。
paypalのサイトやネット上でIPN関連のプログラムは複数公開されている。そのなかで、PHP PayPal IPNというものを利用してwordpressにIPNリスナーを実装してみたい。
https://github.com/Quixotix/PHP-PayPal-IPN
上のコードをダウンロードすると、
ipnlistener.php
というファイルがあるので、そのファイルをwordpressのルート直下にlibというディレクトリを作成し、その中にコピーした。次に、PHP PayPal IPNの
example/ipn.php
というファイルをwordpressのルート下に
paypal.php
というファイル名にしてコピーした。
paypal.php内では、ipnlistener.phpのインクルード設定を行っているので、パスを以下のように修正する。
include('./lib/ipnlistener.php');
個人的にエラーログのファイル名を以下のように変更した。
ini_set('error_log', './ipn.log');
paypal.phpの下の方にメールアドレスを設定する部分があるので、
YOUR EMAIL ADDRESS
という部分を
自身のアドレスに変更しておく。
パスやメールアドレスを修正したら、paypal.phpにブラウザでアクセスしてみる。blog.netというマルチサイト構成のwordpressを想定し、
sub1.blog.net/paypal.php
にブラウザからアクセスしてみる。画面が真っ白で何も表示されないことを確認する。画面には何も表示されないが、wordpressルート直下に
ipn.log
というファイルが新しく生成されたことを確認できる。ファイルを開くと、
[08-Feb-2014 09:24:10] Invalid HTTP request method.
とログが残っていることを確認できる。POSTリクエストでないと上のエラーになるようだ。paypalからのipn通知はPOSTで送信されてくる、そのためPOST以外のリクエストは上のエラーになるように設定されているようだ。
それでは、POSTリクエストをテストとして受け付けるにはどうしたらよいか?
IPN simulator
という開発ツールがpaypalのサイトに用意されているので、それを利用して自分のサイトに通知する。
サイトにアクセスすると、IPN handler URLという項目があるので、そこにIPNリスナーのURLを入力する。今回の場合であれば、
sub1.blog.net/paypal.php
が該当する。このURLはsub1.blog.net専用のIPNリスナーになるが、sub2.blog.netなどマルチサイト環境のそのほかのブログサイトとpaypal.phpを共有することになる。IPNリスナーを共有するが、リクエストURLは、個々のブログサイトで専用のURLを割り当てるとログ管理上有利になることがあるので、そのような想定で進めていく。リクエストURLの設定は、paypalの管理画面から行うことができるが、
<input type="hidden" value="http://sub1.blog.net/paypal.php" name="notify_url">
というコードを購入ボタンのフォーム内に定義することで、リクエストURLを設定することもできる。各ブログサイトでリクエストURLが異なる場合にはこの方法が有効となる。
IPN handler URLを入力したら、そのほかの項目はデフォルトの状態で、下の方にあるSend IPNのボタンを押してみる。ボタンを押すと、
- paypalからのIPN通知
- blog.netがIPN通知を受信
- blog.netがIPNの内容をポストバック
- paypalがポストバックの内容を検証し結果をblog.netに返す
- blog.netが検証結果を受信
という流れで処理が行われる。そのため、上で設定したメールアドレスに検証結果が届くことになっている。しかし、メールは届かない。もう一度、ipn.logを確認してみると、以下のエラーが記録されていることに気づく。
[08-Feb-2014 09:38:00] cURL error: [60] SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
これはCurl接続で利用しているセキュリティ証明書が無効であるためエラーになったという内容のエラーになる。このエラーを回避するためには有効な証明書を設定するか、証明書の検証処理をスルーするように設定する必要がある。今回は、以下のように検証処理を回避する方法で対応した。
lib/ipnlistener.php
でCurlの接続オプションを設定しているので、その一部を変更する。
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
以下のように変更
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
変更したら再度IPN simulatorでIPN通知を送ってみる。今度はメールが届く。
メールには$_POSTで取得できるデータが記入されている
メールには、主題として検証結果の
- VERIFIED
- INVALID
が書かれていて、本文にはIPN simulatorから送信した購入に関する情報が書いてある。これらの情報がpaypal側の購入ステータスが変化するたびに送信されてくる。そのため、paypal.phpでメールを送信するタイミングでデータベース処理を行い、検証結果や購入に関するデータを追加・アップデートを行うことになる。
データベーステーブルの定義
paypalから返されるデータを$_POSTで扱うことができることがわかった。それらのデータを管理するデータベーステーブルが必要になる。レスポンスされるデータが多いためとまどうかもしれないが、効率的にテーブルを定義する方法がある。
PHP PayPal IPNモジュールには、データベース連携の処理は含まれていないが、db連携を含むIPN関連のプログラムが公開されている。それらのプログラムには、テーブル定義のためのSQLが含まれているので、そのSQLを参考にどのようにpaypalのデータを管理しているのか調べてみるのがおすすめ。以下のモジュールはテーブル定義用のSQLが含まれている。
https://github.com/webtechnick/CakePHP-Paypal-IPN-Plugin
https://github.com/orderly/codeigniter-paypal-ipn
CakePHP-Paypal-IPN-Pluginの場合であれば、ルート直下にpaypal_ipn.sqlというDDLが配置されている。文字コードの変更などは必要になるが、効率的にpaypalのテーブルを作成するための助けになるはず。
paypal.phpでwordpress関数を利用可能にする
paypal.phpは、wordpress直下に配置した。この状態では、wordpressの機能を利用することができない。データを管理する際には、wordpressのwpdbを利用して効率的にデータを追加できるようにしたい。wordpress関数を利用可能にするためには、以下の一行を追加する。
require( dirname(__FILE__) . '/wp-load.php' );
この一行で$wpdbが利用可能になる。IPNの検証結果をデータベースに挿入してみる。
global $wpdb; $wpdb->insert('instant_payment_notifications', array( 'id' => sha1(uniqid(mt_rand(), true)), 'payment_status' => $_POST['payment_status'], 'txn_id' => $_POST['txn_id'], 'receiver_email' => $_POST['receiver_email'], 'mc_gross' => $_POST['mc_gross'] ), array( '%s', '%s', '%s', '%s', '%d' ) );
メール送信前に上のコードをpaypal.phpに追加しIPN simulatorでリクエストしてみるとinstant_payment_notificationsテーブルにデータが追加されていくことを確認できる。今回は、必ず検証すべきデータとされているものだけをinsertするコードを書いてみた。
参考