PayPal決済モジュールについていろいろ思うところがあったのですが、
/html/user_data/paypal_recv.php
のソースを見た感じですと、チェックが甘いような気がします。
「設定情報のメールアドレスと receiver_email が一致するかどうか」しかチェックしていないようですので、チェックルーチンを作ってみました。
自身はPHPの知識が殆ど無いので(perlばかりです)EC-CUBEの元ソースからの引用&組み合わせのコードですので無駄が多いかもしれません。
一応PayPalのsandboxでチェック済みです。
添削してくださる方がいらっしゃれば幸いです。
ここに投稿して良いものか悩みましたがよかったでしょうか?
何かの役に立てればと思い投稿してみました。
スキル不足でAPIベースのエクスプレスチェックアウト対応はちょっと難しそうですので
dtb_order テーブルの memo02、memo03、memo04 を使っていますが問題ないでしょうか?
まぁ、
$arrVal['memo03'] = $arrRequest['mc_gross'];
$arrVal['memo04'] = $arrRequest['mc_currency'];
あたりは必要ないと思いますが・・・。
以下改良済み 全ソース --------------------
<?php
require_once('../require.php');
require_once(MODULE_PATH . 'mdl_paypal/LC_Page_Mdl_Paypal_Config.php');
require_once(DATA_PATH. 'module/Request.php');
// POST 以外は Status 400 を返す
if ($_SERVER["REQUEST_METHOD"] != "POST") {
GC_Utils::gfPrintLog($_SERVER["REQUEST_METHOD"] . " Requests by" . print_r($_REQUEST, true), PAYPAL_LOG_PATH);
header("HTTP/1.1 400 Bad Request");
exit;
}
// 決済モジュール設定情報を取得
$objConfig = new LC_Page_Mdl_Paypal_Config();
$arrConfig = $objConfig->getConfig();
$arrErr = array();
GC_Utils::gfPrintLog(
"************************** PayPal IPN receive START *************************",
PAYPAL_LOG_PATH);
GC_Utils::gfPrintLog("Received Parameters by..." , PAYPAL_LOG_PATH);
foreach ($_POST as $key => $val) {
GC_Utils::gfPrintLog($key . " => ". mb_convert_encoding($val, CHAR_CODE), PAYPAL_LOG_PATH);
}
// MY PayPal IPN 追加チェック項目 2010-09-29
// 受注情報の取得
$objQuery = new SC_Query();
$where = "order_id = ?";
$arrRet = $objQuery->select("*", "dtb_order", $where, array($_POST['invoice']));
$arrOrder = $arrRet[0];
// オーダー内容の金額と mc_gross が一致するかどうか
if($arrOrder['payment_total'] != $_POST['mc_gross']){
GC_Utils::gfPrintLog("Illegal mc_gross!", PAYPAL_LOG_PATH);
GC_Utils::gfPrintLog(
"************************** PayPal IPN payment_total Failed! ***********************",
PAYPAL_LOG_PATH);
header("HTTP/1.1 400 Bad Request");
exit;
}
// 支払われた通貨が日本円かどうか PAYPAL_CURRENCY_CODE
if(PAYPAL_CURRENCY_CODE != $_POST['mc_currency']){
GC_Utils::gfPrintLog("Illegal mc_currency!", PAYPAL_LOG_PATH);
GC_Utils::gfPrintLog(
"************************** PayPal IPN mc_currency Failed! ***********************",
PAYPAL_LOG_PATH);
header("HTTP/1.1 400 Bad Request");
exit;
}
// すでに使用済みの txn_id ではないか
$where = "memo02 = ?";
$arrRet = $objQuery->select("*", "dtb_order", $where, array($_POST['txn_id']));
$arrOrder = $arrRet[0];
if($arrOrder){
GC_Utils::gfPrintLog("Illegal txn_id!", PAYPAL_LOG_PATH);
GC_Utils::gfPrintLog(
"************************** PayPal IPN txn_id Failed! ***********************",
PAYPAL_LOG_PATH);
header("HTTP/1.1 400 Bad Request");
exit;
}
//----------------------------------------------------------
// 設定情報のメールアドレスと receiver_email が一致するかどうか
if ($arrConfig['business'] != $_POST['receiver_email']) {
GC_Utils::gfPrintLog("Illegal receiver_email!", PAYPAL_LOG_PATH);
GC_Utils::gfPrintLog(
"************************** PayPal IPN receive Failed! ***********************",
PAYPAL_LOG_PATH);
header("HTTP/1.1 400 Bad Request");
exit;
}
// 受信した情報を元に受注情報を更新する
$result = sfUpdatePaypalOrder($arrConfig, $_POST);
if (!$result) {
$arrErr['IPN Failed'] = "Returned IPN INVALID Status!";
}
if (empty($arrErr)) {
GC_Utils::gfPrintLog(
"************************** PayPal IPN receive Complete!***********************",
PAYPAL_LOG_PATH);
} else {
foreach ($arrErr as $key => $val) {
GC_Utils::gfPrintLog($key . " => ". $val, PAYPAL_LOG_PATH);
}
GC_Utils::gfPrintLog(
"************************** PayPal IPN receive Failed! ***********************",
PAYPAL_LOG_PATH);
}
/**
* リクエストの内容に応じて受注情報を更新する.
*
* @param array $arrConfig PayPal決済モジュールの設定情報
* @param array $arrRequest 受信したリクエスト
* @return boolean PayPalサーバーから VERIFIED を受信した場合 true
*/
function sfUpdatePaypalOrder($arrConfig, $arrRequest) {
switch ($arrRequest['payment_status']) {
case "Denied":
case "Canceled_Reversal":
case "Failed":
case "Refunded":
case "Reversed":
$arrVal['status'] = ORDER_CANCEL;
break;
case "Completed":
$arrVal['status'] = ORDER_PRE_END;
break;
default:
$arrVal['status'] = ORDER_PAY_WAIT;
}
$arrRequest['cmd'] = "_notify-validate";
$response = sendRequest($arrConfig['link_url'], $arrRequest);
if (in_array('VERIFIED', $response)) {
GC_Utils::gfPrintLog("IPN VERIFIED: status by ". $arrRequest['payment_status'], PAYPAL_LOG_PATH);
// MY 2010-09-29追記 dtb_order にPayPal決済時の返り値を追加
$arrVal['memo02'] = $arrRequest['txn_id'];
$arrVal['memo03'] = $arrRequest['mc_gross'];
$arrVal['memo04'] = $arrRequest['mc_currency'];
//-----------------------------------
$objQuery = new SC_Query();
$objQuery->update("dtb_order", $arrVal, "order_id = ?", array($arrRequest['invoice']));
return true;
} else {
return false;
}
}
/**
* リクエスト送信
*/
function sendRequest($link_url, $arrSend) {
// リクエスト設定
$req = new HTTP_Request($link_url);
$req->setMethod(HTTP_REQUEST_METHOD_POST);
// 送信
$req->addPostDataArray($arrSend);
$response = $req->sendRequest();
$req->clearPostData();
// 通信エラーチェック
if (!PEAR::isError($response)) {
$body = $req->getResponseBody();
$err_flg = false;
} else {
$mess = mb_convert_encoding($response->getMessage(), CHAR_CODE);
$err_flg = true;
}
// レスポンス整理
if (!$err_flg) {
$res = putResponse($body);
return $res;
} else {
return $mess;
}
}
/**
* レスポンス整理
*/
function putResponse($body) {
$body = split("\r\n", $body);
$logtext = "\n************ Response start ************";
foreach ($body as $item) {
$logtext .= "\n". $item;
}
$logtext .= "\n************ Response end ************";
GC_Utils::gfPrintLog($logtext, PAYPAL_LOG_PATH);
return $body;
}
?>