Skip to content

Instantly share code, notes, and snippets.

@kidino
Created November 21, 2024 08:18
Show Gist options
  • Save kidino/800c59559c804e45bf0c7430d37c4520 to your computer and use it in GitHub Desktop.
Save kidino/800c59559c804e45bf0c7430d37c4520 to your computer and use it in GitHub Desktop.
SecurePay on Laravel
<?php
namespace App\Http\Controllers;
use Carbon\Carbon;
use App\Models\Plan;
use App\Models\User;
use App\Models\Payment;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class CheckoutController extends Controller
{
/**
* public function index() -- used in routing
* -- to redirect to payment gateway
*
* public function verify() -- used in routing
* -- returning from payment gateway
**/
/**
* protected function record_payment()
* -- to create a payment record before going to payment gateway
*
* protected function process_payment()
* -- to process payment & membership after returning from payment gateway
*
* protected function {payment-gateway}_go()
* -- called by index() based on selected payment gateway
*
* protected function {payment-gateway}_verify()
* -- called by verified based on selected payment gateway
*/
/**
*
* /checkout/{plan}/{payment_gateway}
*/
protected const PG_NAMESPACE = "\\App\\Libraries\\PaymentGateway\\";
public function index(Request $request, Plan $plan, $payment_method) {
// dd($plan, $payment_method);
if(!in_array($payment_method, Payment::SUPPORTED_PAYMENTS)) {
abort(405, 'Unknown payment method');
}
$payment = $this->record_payment($plan, $payment_method);
$pg_classname = self::PG_NAMESPACE . ucfirst( $payment_method );
$payment_gateway = new $pg_classname();
$redirect_url = $payment_gateway->go($plan, $payment);
return redirect( $redirect_url );
}
protected function record_payment(Plan $plan, $payment_method) {
$user = Auth::user();
return Payment::create([
'plan_id' => $plan->id,
'user_id' => $user->id,
'amount' => $plan->price,
'payment_method' => $payment_method,
'payment_status' => 'pending',
'payment_code' => Str::random(20),
'remarks' => ucfirst($payment_method). ' payment for '. $plan->code
]);
}
/* /verify/{payment}/{payment_gateway}
*
*/
public function verify(Request $request, Payment $payment, $payment_method) {
if(!in_array($payment_method, Payment::SUPPORTED_PAYMENTS)) {
abort(405, 'Unknown payment method');
}
$pg_classname = self::PG_NAMESPACE . ucfirst( $payment_method );
$payment_gateway = new $pg_classname();
$result = $payment_gateway->verify( $request, $payment );
if($result['success'] && ($payment->payment_status == 'pending')) {
$this->process_payment($payment);
}
return view('checkout.thankyou');
}
protected function process_payment(Payment $payment) {
$user = User::find( $payment->user_id );
$plan = Plan::find( $payment->plan_id );
$duration = 0;
switch( $plan->term ) {
case 'monthly' : $duration = '1 month'; break;
case 'yearly' : $duration = '1 year'; break;
case 'lifetime' : $duration = '1000 years'; break;
}
if( Carbon::parse( $user->expiry_date )->isFuture() ) {
$user->expiry_date = Carbon::parse( $user->expiry_date )->add( $plan->duration );
} else {
$user->expiry_date = Carbon::today()->add( $duration );
}
$user->plan_id = $plan->id;
$user->save();
$payment->payment_status = 'completed';
$payment->save();
return true;
}
}
<?php
namespace App\Libraries\PaymentGateway;
use App\Models\Plan;
use App\Models\User;
use App\Models\Payment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class Securepay {
private $uid;
private $auth_token;
private $checksum_token;
private $api_url;
function __construct() {
$this->api_url = 'https://'. ( (env('APP_ENV') == 'local') ? 'sandbox.' : '') .'securepay.my/api/v1/payments';
$this->uid = env('SECUREPAY_UID');
$this->auth_token = env('SECUREPAY_AUTH_TOKEN');
$this->checksum_token = env('SECUREPAY_CHECKSUM_TOKEN');
}
function go(Plan $plan, Payment $payment) {
$user = User::find($payment->user_id);
$buyer_phone = null;
$verify_url = route('checkout.verify', [
'payment' => $payment->payment_code,
'payment_method' => 'securepay'
]);
$string = $user->email .'|'.
$user->name.'|'.
$buyer_phone.'|'.
$verify_url.'|'.
$payment->payment_code.'|'.
$payment->remarks.'|'.
$verify_url.'|'.
$payment->amount.'|'.
$this->uid;
$sign = hash_hmac('sha256', $string, $this->checksum_token );
$post_data = 'buyer_name=' . urlencode( $user->name ) .
'&token=' . urlencode( $this->auth_token ) .
'&callback_url=' . urlencode( $verify_url ) .
'&redirect_url=' . urlencode( $verify_url ) .
'&order_number=' . urlencode( $payment->payment_code ) .
'&buyer_email=' . urlencode( $user->email ) .
'&buyer_phone=' . urlencode( $buyer_phone ) .
'&transaction_amount=' . urlencode( $payment->amount ) .
'&product_description=' . urlencode( $payment->remarks ) .
'&redirect_post=' . urlencode( 'true' ) .
'&checksum=' . urlencode( $sign );
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $this->api_url);
curl_setopt($ch, CURLOPT_POST, 1 );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1);
if( env('APP_ENV') == 'local') {
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0);
}
$output = curl_exec( $ch );
echo $output;
// dd($string, $sign, $output);
// return 'https://securepay.my';
}
function verify(Request $request, Payment $payment) {
// dd($request);
$data = $request->all();
$user = User::find($payment->user_id);
if(
($data['transaction_amount_received'] == $payment->amount)
&& ($data['payment_status'] == 'true')
&& ($data['currency'] == 'MYR')
) {
Auth::login($user);
return [
'success' => true
];
}
return [
'success' => false,
'errors' => []
];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment