PayPal API決済の実装サンプル (PHP)

PayPal API決済をPHPで実装する方法について、簡潔に纏めます。

# リファレンス
[PayPal API 決済 ](https://www.paypal.com/jp/webapps/mpp/developer/standard-service/api)

# PayPal API決済 実装のお約束
## 決済実行の流れ
下記順番でPayPal API決済処理を実行していきます。

* 1. PayPal決済開始API(SetExpressCheckout)実行
* 2. PayPal決済開始APIから返却されたTokenを取得
* ３. 取得したTokenをキーにPayPalへリダイレクト
* ４. ユーザ側の決済処理完了後、PayPalからリダイレクトされたタイミングでPayPal決済API(DoExpressCheckoutPayment)を実行
* ５. PayPal決済APIのレスポンス（トランザクションID、ステータスなど）を取得

# PayPal API決済 サンプルコード(PHP)
PayPal API決済のサンプルコードを下記に記載する。
PayPalの接続先はSandBoxを利用しています。

## PayPal決済開始
```php
$POST_DATA = array(
    'USER' => 'ユーザ名',
    'PWD' => 'パスワード',
    'SIGNATURE' => 'APIトークン',
    'METHOD' => 'SetExpressCheckout',
    'VERSION' => 124,
    'PAYMENTREQUEST_0_AMT' => 10000,
    'PAYMENTREQUEST_0_CURRENCYCODE' => 'JPY',
    'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
    'cancelUrl' => 'キャンセル時の遷移先を指定',
    'returnUrl' => '成功時の遷移先を指定',
    'PAYMENTREQUEST_0_SHIPTONAME' => '田中太郎',
    'PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE' => '日本'
);

$curl = curl_init("https://api-3t.sandbox.paypal.com/nvp");
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($POST_DATA));
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);

$output = curl_exec($curl);
$token = substr($output, 6, 22); // Token取得

$redirect_url = "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&useraction=commit&token=" . $token;
header("Location: " . $redirect_url); // 取得したTokenをセットし、PaｙPalへリダイレクト

return;
```

## PayPal決済実行
```php
$url = $_SERVER['HTTP_REFERER'];
$url = parse_url($url);
if (strpos($url['host'], 'paypal.com') === false) {
    return; // paypal以外のリダイレクト
}

// paypalからのリダイレクト時のクエリパラメータより、Tokenなどを取得
$token = $_GET[token];
$payer_id = $_GET[PayerID];

$POST_DATA = array(
    'USER' => 'ユーザ名',
    'PWD' => 'パスワード',
    'SIGNATURE' => 'APIトークン',
    'METHOD' => 'DoExpressCheckoutPayment',
    'VERSION' => 124,
    'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
    'PAYMENTREQUEST_0_AMT' => 10000,
    'PAYMENTREQUEST_0_CURRENCYCODE' => 'JPY',
    'TOKEN' => $token,
    'PAYERID' => $payer_id
);
$curl = curl_init("https://api-3t.sandbox.paypal.com/nvp");
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($POST_DATA));
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);

$output = curl_exec($curl);
$arr = explode('&', $output);

$txn_id;
$payment_status;
$error_code;

foreach ($arr as $line) {
    if ($txn_id !== "" && $payment_status !== "" && $error_code !== "") {
        break;
    }
    if (strpos($line, 'PAYMENTINFO_0_TRANSACTIONID=') !== false) {
        $txn_id = str_replace('PAYMENTINFO_0_TRANSACTIONID=', "", $line);
        continue;
    }
    if (strpos($line, 'PAYMENTINFO_0_PAYMENTSTATUS=') !== false) {
        $payment_status = str_replace('PAYMENTINFO_0_PAYMENTSTATUS=', "", $line);
        continue;
    }
    if (strpos($line, 'PAYMENTINFO_0_ERRORCODE=') !== false) {
        $error_code = str_replace('PAYMENTINFO_0_ERRORCODE=', "", $line);
    }
}

// 以下、後続処理続行

```