如何使用 Braintree 将 creditCard 选项替换为 nonce?

How to replace the creditCard option with nonce using Braintree?

我有一个集成了 braintree 支付网关的应用程序。我使用的是自定义表单而不是直接插入 UI,我使用 creditCard 参数从客户的信用卡进行一次性交易。我最近发现 creditCard 参数已被弃用,并引入了一个新参数 paymentMethodNonce 我之前的代码是

Braintree_Configuration::environment('sandbox');
Braintree_Configuration::merchantId('xxxxxx');
Braintree_Configuration::publicKey('xxxxxx');
Braintree_Configuration::privateKey('xxxxxxxxxxxxxxxxx');

$result = Braintree_Transaction::sale(array(
            'amount' => $price,
            'creditCard' => array(
                'number' => $card_number,
                'cardholderName' => $card_name,
                'expirationDate' => $expirationDate,
                'cvv' => $cvv
            )
));

根据文档,我需要使用隐藏的输入字段在表单中发送令牌以进行交易,我按以下方式在表单中添加了令牌

<input type="hidden" name="payment_method_nonce" id="payment_method_nonce" value="<?=Braintree_ClientToken::generate()?>" />

在我提交表单的另一页上,我使用文档将代码更改为以下内容,但我仍然收到验证错误

Payment method token is invalid.

$payment_method_nonce   =   $_POST['payment_method_nonce'];
$result  = Braintree_Transaction::sale([
    'amount' => '25.00',
    'paymentMethodToken' => $payment_method_nonce,
    'options' => [
      'submitForSettlement' => True
    ]
  ]);

已编辑

这是更新后的代码

index.php

 <?php
    include 'db.php';
    include 'functions.php';
    require_once 'braintree-php-3.13.0/lib/Braintree.php';
    Braintree_Configuration::environment('sandbox');
    Braintree_Configuration::merchantId('xxxxxx');
    Braintree_Configuration::publicKey('xxxxxxx');
    Braintree_Configuration::privateKey('xxxxxx');
    $payment_method_nonce=  Braintree_ClientToken::generate();
?>
<script type="text/javascript" src="../../public_html/js/jquery.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<script type="text/javascript" src="js/jquery.creditCardValidator.js"></script>
<script type="text/javascript" src="js/card.js"></script>
<link rel="stylesheet" href="style.css">


<style>
    label, input { display:block; }
    input.text { margin-bottom:12px; width:95%; padding: .4em; }
    fieldset { padding:0; border:0; margin-top:25px; }
    h1 { font-size: 1.2em; margin: .6em 0; }
    div#users-contain { width: 350px; margin: 20px 0; }
    div#users-contain table { margin: 1em 0; border-collapse: collapse; width: 100%; }
    div#users-contain table td, div#users-contain table th { border: 1px solid #eee; padding: .6em 10px; text-align: left; }
    .ui-dialog .ui-state-error { padding: .3em; }
    .validateTips { border: 1px solid transparent; padding: 0.3em; }
</style>


<script type="text/javascript">
    //    braintree dialouge
    var form;
    $(document).ready(function () {
        dialog = $("#dialog-form").dialog({
            autoOpen: false,
            height: 500,
            width: 500,
            modal: true,
            close: function () {
                form[0].reset();
            }
        });

//        form = dialog.find("form").on("submit", function (event) {
//            event.preventDefault();
//        });

        $("#create-user").button().on("click", function () {
            dialog.dialog("open");
        });
        console.log("Here");



    });

</script>

<button name="create-user" id="create-user">Open Dialouge</button>
<div id="dialog-form" style="display:none;">
    <form method="post"  id="paymentForm" action="cardprocess.php">

        <ul>
            <li>
                <label>Card Number </label>
                <input type="text" name="card_number" id="card_number"  maxlength="20" placeholder="1234 5678 9012 3456"/>
            </li>
<!--            <li>
                <label>Name on Card</label>
                <input type="text" name="card_name" id="card_name" placeholder="Card Holder Name"/>
            </li>-->
            <li class="vertical">
                <ul>
                    <li>
                        <label>Expires</label>
                        <input type="text" name="expiry_month" id="expiry_month" maxlength="2" placeholder="MM" class="inputLeft" />
                        <input type="text" name="expiry_year" id="expiry_year" maxlength="2" placeholder="YY" class="inputLeft" />
                    </li>
                    <li>
                        <label>CVV</label>
                        <input type="text" name="cvv" id="cvv" maxlength="3" placeholder="123" class="inputLeft" />
                    </li>
                </ul>
            </li>
            <li>
                <input type="submit" id="paymentButton" value="Proceed" disabled="true" class="disable">
            </li>
        </ul>
    </form>
</div>
<div id="orderInfo"></div>
<script src="https://js.braintreegateway.com/js/braintree-2.26.0.min.js"></script>
<script type="text/javascript">
     braintree.setup('<?=$payment_method_nonce?>', 'custom', {
            id: "paymentForm",
            hostedFields: {
                number: {
                  selector: "#card_number"
                },
                expirationMonth: {
                  selector: "#expiry_month"
                },
                expirationYear: {
                  selector: "#expiry_year"
                },
                cvv: {
                  selector: "#cvv"
                },
          },
          onError:function (errorObj){
              console.log(errorObj.type);
              console.log(errorObj.message);
          }
        });
</script>

cardprocess.php

    <?php

    include 'db.php';
    include 'functions.php';       

    $price = '1000';
require_once 'braintree-php-3.13.0/lib/Braintree.php';
        Braintree_Configuration::environment('sandbox');
        Braintree_Configuration::merchantId('xxxx');
        Braintree_Configuration::publicKey('xxxx');
        Braintree_Configuration::privateKey('xxxxxxx');
    if ($_SERVER["REQUEST_METHOD"] == "POST") {

        $payment_method_nonce   =   $_POST['payment_method_nonce'];




        $result  = Braintree_Transaction::sale([
            'amount' => '25.00',
            'paymentMethodNonce' => $payment_method_nonce,
            'options' => [
              'submitForSettlement' => True
            ]
          ]);

        if ($result->success) {
            if ($result->transaction->id) {
                $braintreeCode = $result->transaction->id;
                echo "<pre>";
                print_r($braintreeCode);
                //updateUserOrder($braintreeCode, $session_user_id);
            }
        } else if ($result->transaction) {
            echo '{"OrderStatus": [{"status":"2"}]}';
        } else {
            print_r($result);
            echo '{"OrderStatus": [{"status":"0"}]}';
        }
    }
    ?>

```

完全披露:我在 Braintree 工作。如果您有任何其他问题,请随时联系 support

Braintree 客户端令牌和支付方式随机数是两个不同的元素。客户端令牌应在您的服务器上生成,并用于 configure the JavaScript SDK 令牌和 HTML 表单的 DOM ID;之后,您无需担心自己添加和填充隐藏字段。在提交表单时,Braintree 创建一个支付方式随机数并通过隐藏输入将其与表单一起发送。

在服务器端,您的代码也需要稍作调整:您当前发送的是 paymentMethodToken,它指的是现有支付方式的唯一标识符。 nonce 的密钥应该改为 paymentMethodNonce,如 credit card guide.

中所述
$payment_method_nonce = $_POST['payment_method_nonce'];
$result  = Braintree_Transaction::sale([
    'amount' => '25.00',
    'paymentMethodNonce’ => $payment_method_nonce,
    'options' => [
      'submitForSettlement' => True
    ]
 ]);