如何使用 Stripe JS 订阅可变金额的经常性捐赠计划 PHP

How to do a variable amount recurent donation plan subscription with Stripe JS PHP

我不是疯狂的编码专家,但我想使用具有以下功能的 Stripe 灯箱表单:

问题:

所以这是我的代码,我的想法是生成一个日期并使用它来创建一个唯一的计划 ID,但它不起作用,我不确定这是最好的方法,我读了这个但我迷路了,我不知道如何至 https://support.stripe.com/questions/metered-subscription-billing

此外,我将使用此表单通过插件 php-code-for-posts 将其包含到我的 wordpress 中 (看起来可以找到,但我不知道它是否是最佳实践和安全方式,构建插件对我来说太复杂了)

所以这是我的文件结构:

代码灵感来自https://jsfiddle.net/ywain/g2ufa8xr/

我输入了一些代码 // !!关于我的问题的信息

config.php

<?php
// require with composer install
require_once('../vendor/autoload.php');

$stripe = array(
  "secret_key"      => "sk_test_ your secret_key",
  "publishable_key" => "pk_test_ your publishable_key"
);

\Stripe\Stripe::setApiKey($stripe['secret_key']);
?>

stripepay.php

<?php require_once('../config.php');?>
<!-- Stripe Panel, This script only work remotely -->
<script src="https://checkout.stripe.com/checkout.js"></script> 
<!-- JQuery auto update CDN -->
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<!-- /////////////////////////////// ONE SHOT PAYMENT ///////////////////////////////// -->
<h2>One Donation</h2>
Please add any value below
<!-- Form and Charge Validation -->
<form id="payment-form" action="charge1" method="POST">
    <input type="number" id="amount" name="amount" value="3000" placeholder="3,000 Minimum" min="3000" step="500.00" />
    <input type="hidden" id="stripeToken" name="stripeToken"/>
    <input type="hidden" id="stripeEmail" name="stripeEmail"/>
</form>
<input type="button" id="btn" value="Donate" class="strbtn">

<script type="text/javascript">
// JS Script Handle amount value and other Stripe options.
var handler = StripeCheckout.configure({
    key: '< ?php echo $stripe['publishable_key']; ?>', // !! Possible to hide from HTML source view ?? 
    image: '../logo.jpg',
    token: function(token) {
        $("#stripeToken").val(token.id);
        $("#stripeEmail").val(token.email);
        $("#payment-form").submit();
    }
  });

 $('#btn').on('click', function(e) {
    var amount = $("#amount").val() *1; // !! normaly it's *1000 but with YEN need to apply this ??
// Open Checkout with further options
    handler.open({
// OPTIONAL, UNCHECK THE // TO ACTIVATE IT:
      //bitcoin: 'true',
      //alipay: 'true',
      billingAddress: 'true',
      zipcode: 'true',
      allowRememberMe: 'true',
      //stripeEmail: 'true', // !! Stripe in test mode doesn't send email confirmation, there is any way to check if it will works ??
      name: 'company name',
      description: 'company description',
      locale: 'auto', // !! on reults it show i'm from USA but i'm in Japan, is it based on navigator ? There is a way to be more accurate ??
      panelLabel: 'DONATE',
      currency: 'jpy',
      amount: amount  
    });
    e.preventDefault();
  });

  // Close Checkout on page navigation
  $(window).on('popstate', function() {
    handler.close();
  });

//to prevent zero amount in the form, add 3000 when focus out of the field  
$(document).ready(function(){
    $("body").delegate('#amount', 'focusout', function(){ // !! There is a better way to make the minimum amount 3000Yen ??
        if($(this).val() < 3000){
            $(this).val('3000');
        }
    });
});
</script>



<!-- /////////////////////////////// ANNUAL PAYMENT SUBSCIPTION ///////////////////////////////// -->
<h2>Annual Recurring Donations</h2>
Please add any value below
<!-- Form and Charge Validation -->
<form id="payment-form2" action="charge2" method="POST">
    <input type="number" id="amount2" name="amount" value="3000" placeholder="3,000 Minimum" min="3000" step="500.00" />
    <input type="hidden" id="stripeToken2" name="stripeToken"/>
    <input type="hidden" id="stripeEmail2" name="stripeEmail"/>
    <input type="hidden" id="idplan" name="idplan"/>
</form>
<input type="button" id="btn2" value="Subscription" class="strbtn">

<script type="text/javascript">
// JS Script Handle amount value and other Stripe options.
var handler = StripeCheckout.configure({
    key: '<?php echo $stripe['publishable_key']; ?>',
    image: '../str-gps-logo.jpg',
    token: function(token) {    
        $("#stripeToken2").val(token.id);
        $("#stripeEmail2").val(token.email);
        $("#payment-form2").submit();
    }
  });


 $('#btn2').on('click', function(e) {
    var amount = $("#amount2").val() *1;
    var plan = $("#idplan").val(Date); // !! Generate Date ID for the Plan to be a unique id value, possible to add milisecond too ??

// Open Checkout with further options
    handler.open({
      billingAddress: 'true',
      zipcode: 'true', // !! is it like this or zip-code: ??
      name: 'Year Plan',
      description: 'Variable Amount Year Plan',
      locale: 'auto',
      panelLabel: 'Subscribe',
      currency: 'jpy',
      amount: amount 
    });
    e.preventDefault(); 
    });

  // Close Checkout on page navigation
  $(window).on('popstate', function() {
    handler.close();
  });

//to prevent zero amount in the form, add 3000 when focus out of the field  
$(document).ready(function(){
    $("body").delegate('#amount2', 'focusout', function(){
        if($(this).val() < 3000){
            $(this).val('3000');
        }
    });
});

</script>

charge.php

<?php
  require_once('./config.php');

// Check if the user have javascript and if the token is validated.
// !! code below needed or more simple with   $token = $_POST['stripeToken'];   ??

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $errors = array();
    if (isset($_POST['stripeToken'])) {
        $token = $_POST['stripeToken'];
    } else {
        $errors['token'] = 'The order cannot be processed. You have not been charged. 
                            Please confirm that you have JavaScript enabled and try again.';
    }
}

// Create the Customer: 
  $customer = \Stripe\Customer::create(array( 
      'email' => $_POST['stripeEmail'],
      'source'  => $token
  ));

// Create the Charge:
  $charge = \Stripe\Charge::create(array(
      'customer' => $customer->id,
      'amount'   => $_POST['amount'],
      'currency' => 'jpy'
  ));

  echo '<h1>Thanks for your donation ! </h1>'; // !! There is a way to show error to user and redirect to index ?

?>

charge2.php

<?php
  require_once('./config.php');

// Check if the user have javascript and if the token is validated.
//$token  = $_POST['stripeToken'];
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $errors = array();
    if (isset($_POST['stripeToken'])) {
        $token = $_POST['stripeToken'];
    } else {
        $errors['token'] = 'The order cannot be processed. You have not been charged. 
                            Please confirm that you have JavaScript enabled and try again.';
    }
}

// TEST 1 inspired from  

// !! Find the way to generate unique id to create the plan or any other solution for a variable amount recurent donation plan subscription

$plan = \Stripe\Plan::create(array(
        'name' => $_POST['idplan'],
        'id' => $_POST['idplan'],
        'interval' => 'day', // !! interval daily for testing purpose but the final will be in years 
        'interval_count' => '1',
        'currency' => 'jpy',
        'amount' => $_POST['amount']    
    ));

$customer = \Stripe\Customer::create(array( 
      'source'  => $token,
      'email' => $_POST['stripeEmail'],
      'plan'  => $_POST['idplan'],
      'description' => 'plan description'
    ));

echo '<h1>Thanks for your annual donation ! </h1>';
?>

我确信有一种方法可以使只有一个收费文件并且更少的 id 混乱变得更干净,但我也不知道如何...

但如果你能帮助我解决主要问题,我将不胜感激,这段代码让我抓狂!

干杯!

In the form i use a technic to make the user to pay minimum 3000 YEN if he change the value to 0 for exemple when he focus out the input area in become 3000 again that's why i use value="3000" but it will be nicer if it can be only placeholder="3,000 YEN Minimum"

是否强制执行取决于您。我建议您添加客户端 (Javascript) 和服务器端 (PHP) 检查以确保金额​​高于您的最低金额。

After charge user Stripe doesn't send email confirmation, i read it doesnt do it in test mode, still true ?

是的,Stripe 在测试模式下不会自动发送任何电子邮件收据。您仍然可以在控制面板中查看特定费用并单击 "Send Receipt" 以手动发送收据。

I would like to hide the public key from html source if it's possible

这不可能,但这不是问题。可发布的密钥是公开可见的。它只能用于创建带有 Checkout or Stripe.js 的代币,而代币本身没有任何作用。

The main problem is when user enter a variable amount and validate the form it launch the Stripe lightbox windows then it launch the charge2.php on my server but to create a plan, the amount must be fixed with a unique plan id.

有几种方法可以处理可变数量的订阅。最简单的可能是用 amount=1 创建一个基本计划。然后,当您 create subscriptions to this plan, you'd use the quantity 参数以确保计费的金额正确时。

一个更优雅但稍微复杂一点的解决方案是为每个客户创建一个新计划。在这种情况下,您需要确保每个计划都有一个唯一的 ID——例如,您可以使用客户的电子邮件地址:

$plan_id = "plan_" . $_POST["stripeEmail"];

$plan = \Stripe\Plan::create(array(
    "id" => $plan_id,
    "name" => "Subscription plan for " . $_POST["stripeEmail"],
    "amount" => $_POST["amount"], // amount sent by the customer's browser
    "currency" => "jpy",
    "interval" => "day",
));

$customer = \Stripe\Customer::create(array(
    "email" => $_POST["stripeEmail"],
    "source" => $_POST["stripeToken"], // token returned by Stripe.js/Checkout
    "plan" => $plan_id,
));

实际上,所有对 Stripe 的 API 的调用都应该包含在 try/catch 块中,以确保 errors are handled 正确。