user1606612
user1606612

Reputation: 27

Integrating Card Payments with Codeigniter

I've built a web application and I am looking to integrate cardsave's direct payment API into the application. I was wondering if anyone had any advise on the best way to do this.

Cardsave provide standard code for integrating: Download Gateway Integration Pack ZIP file

When a payment is made I need to store the CrossPaymentsReference and payment amount in my database, the rest I will leave to cardsave's api I have thought of a couple of solutions which should potentially work:

1) Using Views for all of the code and on sucessful payment and use Ajax to update the database with the crossPaymentReference and payment amount on sucessfull completion, because it involves minimal editing of the code, but does have a minor security risk because it sends the reference at the client end.

2) Create a library with the payment system class, put the preprocess payments and process payment code into a controller and copy the form into a view, and just a have a small model to update the database on sucessfull payment's. (I'm guessing this is the best way.)

3) Edit everything and build an MVC version of the code

Upvotes: 1

Views: 3375

Answers (1)

Chris Aelbrecht
Chris Aelbrecht

Reputation: 2091

My latest project runs on CI 2.0. I’ve integrated a payment system such as Card Save with success (in my case I use Ogone, which is a Belgian company).

Below I’ve detailed a bit how I implemented the order and payment system.

The advice I can give you is the following.

  • Keep your products, orders and payments in separate tables. Link products to orders via a reference table (don’t store e.g. a list of product ID’s in a field in the order)
  • Allow that a payment can only have one order, but an order can have multiple payments (but only one paid). This way when a payment fails (e.g. the user pressed cancel on Card Saves payment page), you can just create a new payment on your side and let the user retry (unless Card Save accepts that you do 2 payment request with the same payment ID).
  • Make a separate library (not controller) that handles successfully paid orders. This library would e.g. activate a subscription that the user bought, or make a work order for someone to ship the products. By keeping it in a separate library you can extend its functionality (e.g. if for a specific product you would need to do something new) without touching at your payment logic (thus preventing heavy retesting).
  • Generate hashes when posting data, or redirecting users to checkout pages, pages that prepare the payment and recalculate the hashes each time to prevent that someone tampered with the data you posted or that is in the URL.
  • Make sure everything works without AJAX and add AJAX afterwards.

Basically the ordering process I came up with is divided as follows:

  1. User adds services (I don’t sell physical products) to basket (using a modified version of CI’s shopping cart)
  2. When done user clicks “Order products” which does a POST to the controller Place_order. The controller Place_order does the following things:
    • Check if the user is still logged in (in my case everyone needs to register before)
    • Get the products that are in the shopping cart and checks if they actually exist in the database (you never know)
    • Create a new order in the database and add the products to the order in the DB
  3. Place_order doesn’t output anything, but redirects the user on success to a controller Checkout. Here I don’t use POST. This way you can reuse the URL (e.g. if the user decides to stop, he can continue the payment later). The URL contains the order ID and a hash.
  4. The Checkout controller does the following
    • Recalculate the hash to see if no one tampered with the URL
    • Check if the order exists and isn’t paid yet
    • Check if the order belongs to the user logged in
    • Create the payment if it doesn’t exist yet
    • Show a view with a button “Cancel order” and “Pay order”. This is actually a form that contains in a hidden field the payment ID and a hash of the payment ID.
  5. When clicking “Pay order”, a POST is done to a controller Pay_order. I don’t use GET, because I want that users only come on this page by posting data that was set by the Checkout controller. If they use GET to come on the page an error is thrown. This controller does the following:
    • Recalculate the hash to see of no one tampered with the posted data
    • Check if the payment exists and is not yet paid
    • If all is OK, compose the view that contains the necessary info to be posted to the payment service
    • Show the view.
    • When the user presses “Go to payment service” all data is posted to Ogone where the user executes the payment
  6. When the payment is completed (correct or not) Ogone redirects the user back to me to a controller Payment_successfull or Payment_other (for errors etc). In the Payment_succesfull I call a library Purchase_activator which takes the payment ID as input. This one looks up the order and activates the services the user just paid. In the other case (on error) the user is shown a view with the correct error message and an option to retry or cancel.

Upvotes: 4

Related Questions