Skip to content
Advertisement

PHP/Javascript – Add payment method with Stripe API

I am using WordPress, but I am using an “out of the box” solution because my client requested it specifically. I have this Javascript which creates a form and when the form is submitted it creates a cookie with the token in it, so I can retrieve it from PHP, it looks like this:

<form action="/wp-content/themes/betheme/includes/add_payment_method.php" method="post" id="add-card-form">
      <div class="form-row">
        <label for="card-element">
          Credit or debit card
        </label>

        <div id="card-element"></div>

        <!-- Used to display Element errors. -->
        <div id="card-errors" role="alert"></div>
      </div>

      <button>Add payment method</button>
    </form>

    <script src="https://js.stripe.com/v3/"></script>

    <script>
        var style = {
          base: {
            color: '#ffffff',
            fontSize: '14px',
            fontSmoothing: 'antialiased',
            '::placeholder': {
              color: '#ccc',
            },
            iconColor: "#fff"
          },
          invalid: {
            color: '#e5424d',
            ':focus': {
              color: '#303238',
            },
          },
        };
        var stripe = Stripe('xxxxxxxxxxxxxxxxxxxxxxx');
        var elements = stripe.elements();
        var cardElement = elements.create('card', {style: style, hidePostalCode: true});

        window.mobilecheck = function() {
          var check = false;
          (function(a){if(/(android|bbd+|meego).+mobile|avantgo|bada/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)/|plucker|pocket|psp|series(4|6)0|symbian|treo|up.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
          return check;
        };

        if(mobilecheck()) {
            cardElement.mount('#Content > div > div > div > div.section.mcb-section.hide-desktop > div > div > div > div > div > div > div > form > div.form-row >div#card-element');
        }
        else {
            cardElement.mount('#Content > div > div > div > div.section.mcb-section.hide-tablet.hide-mobile > div > div > div > div > div > div > div > form > div.form-row > div#card-element');
        }

        cardElement.addEventListener('change', function(event) {
          var displayError = document.getElementById('card-errors');
          if (event.error) {
            displayError.textContent = event.error.message;
          } else {
            displayError.textContent = '';
          }
        });

        // Create a token or display an error when the form is submitted.
        var form = document.getElementById('add-card-form');
        form.addEventListener('submit', function(event) {
          event.preventDefault();

          stripe.createToken(cardElement).then(function(result) {
            if (result.error) {
              // Inform the customer that there was an error.
              var errorElement = document.getElementById('card-errors');
              errorElement.textContent = result.error.message;
            } else {
              // Send the token to your server.
              stripeTokenHandler(result.token);
            }
          });
        });

        function createCookie(name, value, days) {
          var expires;
          if (days) {
            var date = new Date();
            date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
            expires = "; expires=" + date.toGMTString();
          } else {
           expires = "";
          }
          document.cookie = escape(name) + "=" + escape(value) + expires + "; path=/";
        }

        function stripeTokenHandler(token) {
            createCookie("stripe_token", token, 1);

            var form = document.getElementById('add-card-form');
            form.submit();
        }
</script>

When the form is submitted, it executes this PHP in add_payment_method.php:

<?php
    require_once("../../../../wp-load.php");
    submit_stripe_payment_method($_COOKIE['stripe_token']);
?>

In my functions.php file for my theme, I have:

require_once('stripe-php/init.php');

....

function submit_stripe_payment_method($token) {
    print_r($token);

    $current_user_id = get_current_user_id();
    echo 'Your User ID is: ' .$current_user_id;

    $customer_id = get_user_meta( $current_user_id, '_stripe_customer_id', true );
    echo "CUSTOMER_ID: ".(string)$customer_id;

    StripeStripe::setApiKey("xxxxxxxxxxxxxxxxxxxxxxx");

    echo "MADE IT HERE";

    $customer = StripeCustomer::retrieve((string)$customer_id);

    echo "CUSTOMER: ".$customer;

    $customer_card = $customer->sources->create(["source" => $token]);
    echo "<pre>";
    var_dump($customer_card);
    echo "</pre>";
}

The output of the above is:

[object Object]Your User ID is: 1CUSTOMER_ID: cus_DsoF18uw1dR0ujMADE IT HERE

As you can see it only gets as far as “MADE IT HERE” echo.

I have verified in the Stripe web console that the $customer_id I am using is correct, and I don’t have any errors, PHP or otherwise. The only thing I can think of is I am using the token wrong but it seems pretty straight forward. As you can see, the $token prints as [Object object], and it does this no matter how I try to log it, so I can’t see exactly what it is, but this makes sense because it contains sensitive information used to validate the credit card…also maybe it never gets to that point because I never see the echo "CUSTOMER: ".$customer; statement, so maybe it gets hung up on:

$customer = StripeCustomer::retrieve((string)$customer_id);

Also, I tried the above without (string) first but got the same result.

So after all of this, I check the Stripe console, and no card has been added.

UPDATE

Apparently the API version I am using is not the latest version, I can upgrade, I just want to know if anyone thinks this is a possible solution before I do it. As it might change how stripe works throughout the site (with the plugin). I am using 2018-02-28 and I can upgrade to 2018-09-24 . I am also testing on localhost environment so I am not https, but I don’t think this matters for testing.

UPDATE

I realized I hadn’t added the endpoint for my localhost setup to the stripe console admin area. To do this I had to use ngrok (as suggested by Stripe if you are using localhost). I am using localhost on port 8888, so I did ./ngrok http 8888 and then tried again and it didn’t work. It does say in WordPress that the endpoint will enable you to receive notifications on the charge statuses. So maybe it isn’t relevant for adding a payment method. I used the http url for ngrok not the https url.

UPDATE

I manually installed stripe-php so I tried with composer but it didn’t help, same result.

UPDATE

I changed my key to the secret key and that allowed me to retrieve the $customer but I don’t see any output for $customer_card and when I look in the dashboard no card has been created.

UPDATE

I checked the Stripe dashboard and I am receiving an error when I try to create the source:

{
  "error": {
    "code": "resource_missing",
    "doc_url": "https://stripe.com/docs/error-codes/resource-missing",
    "message": "No such token: [object Object]",
    "param": "source",
    "type": "invalid_request_error"
  }
}

What am I doing wrong with the token?

UPDATE

Solution to token problem: in test mode, the token is just a string that corresponds with the test credit card number you are using, I needed "tok_visa" for 4242424242424242. https://stripe.com/docs/testing

Advertisement

Answer

The problem might be that in line

StripeStripe::setApiKey(“xxxxxxxxxxxxxxxxxxxxxxx”);

you are using Publishable key starts with pk_xxx, instead you should be using Secret Key sk_xxxx in your account.

You could see the errors from Stripe Dashboard

https://dashboard.stripe.com/test/logs?method%5B%5D=get&method%5B%5D=post&method%5B%5D=delete&direction%5B%5D=connect_in&direction%5B%5D=self

after you login.

Let me know if that helps

EDIT

I also needed to use a testing token, which is just a string that corresponds to the the test credit card number you are using. https://stripe.com/docs/testing. See the Tokens tab.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement