xgenious/paymentgateway 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

xgenious/paymentgateway

Composer 安装命令:

composer require xgenious/paymentgateway

包简介

A Laravel package to manage multiple payment gateways with a unified API

README 文档

README

A Laravel package to manage multiple payment gateways with a unified API.

  • Package: xgenious/paymentgateway
  • Author: Sharifur Rahman
  • License: MIT
  • PHP: ^8.2
  • Laravel: ^12.x

Supported Payment Gateways

# Gateway # Gateway
1 PayPal 2 Stripe
3 Paytm 4 Midtrans
5 Razorpay 6 Mollie
7 Flutterwave 8 Paystack
9 Payfast 10 Cashfree
11 Instamojo 12 Mercado Pago
13 SquarePay 14 CinetPay
15 PayTabs 16 BillPlz
17 Zitopay 18 Toyyibpay
19 Pagali 20 Authorize.Net
21 SitesWay 22 TransactionCloud
23 WiPay 24 KineticPay
25 Senangpay 26 SaltPay
27 Iyzipay 28 Paymob
29 PowertranzPay 30 AwdPay
31 YooMoney 32 CoinPayments
33 SSLCommerz 34 Xendit
35 Adyen 36 Airwallex

Installation

composer require xgenious/paymentgateway

Step 3 — Publish the config file:

php artisan vendor:publish --provider="Xgenious\Paymentgateway\Providers\PaymentgatewayServiceProvider"

This creates config/paymentgateway.php.

Basic Usage

Every gateway follows the same two-method pattern:

  1. charge_customer(array $data) — initiates payment, returns redirect response
  2. ipn_response() — handles the webhook/IPN callback

Common charge_customer parameters

[
    'amount'       => 10,
    'title'        => 'Order #56',
    'description'  => 'Payment for order #56',
    'ipn_url'      => route('payment.gateway.ipn'),
    'order_id'     => 56,
    'track'        => 'unique_tracking_id',
    'cancel_url'   => route('payment.failed'),
    'success_url'  => route('payment.success'),
    'email'        => 'customer@example.com',
    'name'         => 'Customer Name',
    'payment_type' => 'order',
]

Gateway Setup Examples

Stripe

// charge_customer
$stripe = XgPaymentGateway::stripe();
$stripe->setSecretKey('sk_test_...');
$stripe->setPublicKey('pk_test_...');
$stripe->setCurrency('USD');
$stripe->setEnv(true); // true = sandbox, false = live

$response = $stripe->charge_customer([...]);
return $response;

// ipn_response
$stripe = XgPaymentGateway::stripe();
$stripe->setSecretKey('sk_test_...');
$stripe->setPublicKey('pk_test_...');
$stripe->setEnv(true);
dd($stripe->ipn_response());

IPN Route:

Route::post('/stripe-ipn', [PaymentLogController::class, 'stripe_ipn'])->name('payment.stripe.ipn');

PayPal

// charge_customer
$paypal = XgPaymentGateway::paypal();
$paypal->setClientId('client_id');
$paypal->setClientSecret('client_secret');
$paypal->setAppId('app_id');
$paypal->setCurrency('USD');
$paypal->setEnv(true); // true = sandbox

$response = $paypal->charge_customer([...]);
return $response;

// ipn_response
$paypal = XgPaymentGateway::paypal();
$paypal->setClientId('client_id');
$paypal->setClientSecret('client_secret');
$paypal->setAppId('app_id');
$paypal->setEnv(true);
dd($paypal->ipn_response());

IPN Route:

Route::get('/paypal-ipn', [PaymentLogController::class, 'paypal_ipn'])->name('payment.paypal.ipn');

Paytm

// charge_customer
$paytm = XgPaymentGateway::paytm();
$paytm->setMerchantId('your_merchant_id');
$paytm->setMerchantKey('your_merchant_key');
$paytm->setMerchantWebsite('WEBSTAGING');
$paytm->setChannel('WEB');
$paytm->setIndustryType('Retail');
$paytm->setCurrency('INR');
$paytm->setEnv(true); // true = sandbox
$paytm->setExchangeRate(74); // required if currency is not INR

$response = $paytm->charge_customer([...]);
return $response;

// ipn_response
$paytm = XgPaymentGateway::paytm();
$paytm->setMerchantId('your_merchant_id');
$paytm->setMerchantKey('your_merchant_key');
$paytm->setMerchantWebsite('WEBSTAGING');
$paytm->setChannel('WEB');
$paytm->setIndustryType('Retail');
$paytm->setEnv(true);
dd($paytm->ipn_response());

Midtrans

// charge_customer
$midtrans = XgPaymentGateway::midtrans();
$midtrans->setClientKey('your_client_key');
$midtrans->setServerKey('your_server_key');
$midtrans->setCurrency('IDR');
$midtrans->setEnv(true); // true = sandbox
$midtrans->setExchangeRate(14000); // required if currency is not IDR

$response = $midtrans->charge_customer([...]);
return $response;

// ipn_response
$midtrans = XgPaymentGateway::midtrans();
$midtrans->setClientKey('your_client_key');
$midtrans->setServerKey('your_server_key');
$midtrans->setEnv(true);
dd($midtrans->ipn_response());

IPN Route:

Route::get('/midtrans-ipn', [PaymentLogController::class, 'midtrans_ipn'])->name('payment.midtrans.ipn');

Midtrans Test Cards:

VISA (3DS Enabled):      4811 1111 1111 1114
VISA (3DS Disabled):     4411 1111 1111 1118
Mastercard (3DS Enabled): 5211 1111 1111 1117
Mastercard (3DS Disabled): 5410 1111 1111 1116

Razorpay

// charge_customer
$razorpay = XgPaymentGateway::razorpay();
$razorpay->setApiKey('your_api_key');
$razorpay->setApiSecret('your_api_secret');
$razorpay->setCurrency('INR');
$razorpay->setEnv(true);
$razorpay->setExchangeRate(74); // required if currency is not INR

$response = $razorpay->charge_customer([...]);
return $response;

// ipn_response
$razorpay = XgPaymentGateway::razorpay();
$razorpay->setApiKey('your_api_key');
$razorpay->setApiSecret('your_api_secret');
$razorpay->setEnv(true);
dd($razorpay->ipn_response());

Mollie

// charge_customer
$mollie = XgPaymentGateway::mollie();
$mollie->setApiKey('your_api_key');
$mollie->setCurrency('EUR');
$mollie->setEnv(true);

$response = $mollie->charge_customer([...]);
return $response;

// ipn_response
$mollie = XgPaymentGateway::mollie();
$mollie->setApiKey('your_api_key');
$mollie->setCurrency('EUR');
$mollie->setEnv(true);
dd($mollie->ipn_response());

IPN Route:

Route::get('/mollie-ipn', [PaymentLogController::class, 'mollie_ipn'])->name('payment.mollie.ipn');

Flutterwave

// charge_customer
$flutterwave = XgPaymentGateway::flutterwave();
$flutterwave->setPublicKey('your_public_key');
$flutterwave->setSecretKey('your_secret_key');
$flutterwave->setSecretHash('your_secret_hash');
$flutterwave->setCurrency('NGN');
$flutterwave->setEnv(true);

$response = $flutterwave->charge_customer([...]);
return $response;

// ipn_response
$flutterwave = XgPaymentGateway::flutterwave();
$flutterwave->setSecretKey('your_secret_key');
$flutterwave->setSecretHash('your_secret_hash');
$flutterwave->setEnv(true);
dd($flutterwave->ipn_response());

IPN Route:

Route::get('/flutterwave-ipn', [PaymentLogController::class, 'flutterwave_ipn'])->name('payment.flutterwave.ipn');

Flutterwave Test Cards:

Mastercard (PIN): 5531 8866 5214 2950 | CVV: 564 | Expiry: 09/32 | PIN: 3310 | OTP: 12345
Visa:             4556 0527 0417 2643 | CVV: 899 | Expiry: 09/32 | PIN: 3310 | OTP: 12345

Paystack

// charge_customer
$paystack = XgPaymentGateway::paystack();
$paystack->setPublicKey('your_public_key');
$paystack->setSecretKey('your_secret_key');
$paystack->setMerchantEmail('merchant@example.com');
$paystack->setCurrency('NGN');
$paystack->setEnv(true);

$response = $paystack->charge_customer([...]);
return $response;

// ipn_response
$paystack = XgPaymentGateway::paystack();
$paystack->setSecretKey('your_secret_key');
$paystack->setEnv(true);
dd($paystack->ipn_response());

Payfast

// charge_customer
$payfast = XgPaymentGateway::payfast();
$payfast->setMerchantId('your_merchant_id');
$payfast->setMerchantKey('your_merchant_key');
$payfast->setPassphrase('your_passphrase');
$payfast->setCurrency('ZAR');
$payfast->setEnv(true);

$response = $payfast->charge_customer([...]);
return $response;

// ipn_response
$payfast = XgPaymentGateway::payfast();
$payfast->setMerchantId('your_merchant_id');
$payfast->setMerchantKey('your_merchant_key');
$payfast->setPassphrase('your_passphrase');
$payfast->setEnv(true);
dd($payfast->ipn_response());

Cashfree

// charge_customer
$cashfree = XgPaymentGateway::cashfree();
$cashfree->setAppId('your_app_id');
$cashfree->setSecretKey('your_secret_key');
$cashfree->setCurrency('INR');
$cashfree->setEnv(true); // true = test mode

$response = $cashfree->charge_customer([...]);
return $response;

// ipn_response
$cashfree = XgPaymentGateway::cashfree();
$cashfree->setAppId('your_app_id');
$cashfree->setSecretKey('your_secret_key');
$cashfree->setEnv(true);
dd($cashfree->ipn_response());

Instamojo

// charge_customer
$instamojo = XgPaymentGateway::instamojo();
$instamojo->setClientId('your_client_id');
$instamojo->setClientSecret('your_client_secret');
$instamojo->setCurrency('INR');
$instamojo->setEnv(true); // true = test mode

$response = $instamojo->charge_customer([...]);
return $response;

// ipn_response
$instamojo = XgPaymentGateway::instamojo();
$instamojo->setClientId('your_client_id');
$instamojo->setClientSecret('your_client_secret');
$instamojo->setEnv(true);
dd($instamojo->ipn_response());

Mercado Pago

// charge_customer
$mercadopago = XgPaymentGateway::mercadopago();
$mercadopago->setClientId('your_client_id');
$mercadopago->setClientSecret('your_client_secret');
$mercadopago->setCurrency('BRL');
$mercadopago->setEnv(true);

$response = $mercadopago->charge_customer([...]);
return $response;

// ipn_response
$mercadopago = XgPaymentGateway::mercadopago();
$mercadopago->setClientId('your_client_id');
$mercadopago->setClientSecret('your_client_secret');
$mercadopago->setEnv(true);
dd($mercadopago->ipn_response());

CinetPay

$cinetpay = XgPaymentGateway::cinetpay();

See detailed setup: CinetPay.md

Authorize.Net

// charge_customer
$authorizenet = XgPaymentGateway::authorizenet();
$authorizenet->setApiLoginId('your_login_id');
$authorizenet->setTransactionKey('your_transaction_key');
$authorizenet->setCurrency('USD');
$authorizenet->setEnv(true);

$response = $authorizenet->charge_customer([...]);
return $response;

// ipn_response
$authorizenet = XgPaymentGateway::authorizenet();
$authorizenet->setApiLoginId('your_login_id');
$authorizenet->setTransactionKey('your_transaction_key');
$authorizenet->setEnv(true);
dd($authorizenet->ipn_response());

Adyen

See detailed setup: AdyenPay.md

Other Gateways

The following gateways follow the same charge_customer / ipn_response pattern. Refer to the individual gateway class in src/Base/Gateways/ for available setter methods:

Facade Method Gateway
XgPaymentGateway::squareup() SquarePay
XgPaymentGateway::paytabs() PayTabs
XgPaymentGateway::billplz() BillPlz
XgPaymentGateway::zitopay() ZitoPay
XgPaymentGateway::toyyibpay() Toyyibpay
XgPaymentGateway::pagalipay() Pagali
XgPaymentGateway::sitesway() SitesWay
XgPaymentGateway::transactionclud() TransactionCloud
XgPaymentGateway::wipay() WiPay
XgPaymentGateway::kineticpay() KineticPay
XgPaymentGateway::senangpay() Senangpay
XgPaymentGateway::saltpay() SaltPay
XgPaymentGateway::iyzipay() Iyzipay
XgPaymentGateway::paymob() Paymob
XgPaymentGateway::powertranz() PowertranzPay
XgPaymentGateway::awdPay() AwdPay
XgPaymentGateway::yoomoney() YooMoney
XgPaymentGateway::coinpayments() CoinPayments
XgPaymentGateway::sslcommerz() SSLCommerz
XgPaymentGateway::xendit() Xendit
XgPaymentGateway::airwallex() Airwallex
XgPaymentGateway::adyen() Adyen

Developer Guide: Adding a New Gateway

This guide walks through adding a new payment gateway to the package.

Architecture Overview

src/
├── Base/
│   ├── PaymentGatewayBase.php       ← abstract base class all gateways extend
│   ├── PaymentGatewayHelpers.php    ← registers all gateway factory methods
│   └── Gateways/
│       └── YourGatewayPay.php       ← your new gateway class
├── Traits/
│   ├── PaymentEnvironment.php       ← provides setEnv() / getEnv()
│   ├── CurrencySupport.php          ← provides setCurrency() / getCurrency() / setExchangeRate()
│   └── ConvertUsdSupport.php        ← provides get_amount_in_usd() for currency conversion
src/Facades/
│   └── XgPaymentGateway.php         ← the facade users call
config/
│   └── paymentgateway.php           ← gateway credentials config

Every gateway class must extend PaymentGatewayBase and implement six abstract methods.

Step 1 — Create the Gateway Class

Create src/Base/Gateways/YourGatewayPay.php:

<?php

namespace Xgenious\Paymentgateway\Base\Gateways;

use Xgenious\Paymentgateway\Base\PaymentGatewayBase;
use Xgenious\Paymentgateway\Traits\CurrencySupport;
use Xgenious\Paymentgateway\Traits\PaymentEnvironment;
use Xgenious\Paymentgateway\Traits\ConvertUsdSupport; // include if you need USD conversion

class YourGatewayPay extends PaymentGatewayBase
{
    use PaymentEnvironment, CurrencySupport, ConvertUsdSupport;

    // 1. Declare credential properties
    protected string $api_key;
    protected string $secret_key;

    // 2. Add public setters (fluent — return $this)
    public function setApiKey(string $key): static
    {
        $this->api_key = $key;
        return $this;
    }

    public function setSecretKey(string $key): static
    {
        $this->secret_key = $key;
        return $this;
    }

    // 3. Private getters
    private function getApiKey(): string { return $this->api_key; }
    private function getSecretKey(): string { return $this->secret_key; }

    // 4. Implement: convert amount to the unit the gateway expects
    public function charge_amount($amount): float|int
    {
        // If the site currency is natively supported, use it directly.
        // Otherwise, convert to USD (or the gateway's base currency).
        if (in_array($this->getCurrency(), $this->supported_currency_list(), true)) {
            return $amount;
        }
        return $this->get_amount_in_usd($amount);
    }

    // 5. Implement: initiate a payment and redirect the customer
    public function charge_customer(array $args): mixed
    {
        $amount = $this->charge_amount($args['amount']);

        // Call the gateway SDK / HTTP API to create a payment session.
        // $args keys: amount, title, description, ipn_url, order_id,
        //             track, cancel_url, success_url, email, name, payment_type

        $response = YourGatewaySdk::createPayment([
            'amount'      => $amount,
            'currency'    => $this->charge_currency(),
            'redirect_url'=> $args['success_url'],
            'webhook_url' => $args['ipn_url'],
            'reference'   => $args['order_id'],
        ]);

        // Store anything you need to verify the payment later
        session()->put('yourgateway_payment_id', $response->id);
        session()->put('yourgateway_order_id',   $args['order_id']);

        // Return a redirect to the hosted payment page
        return redirect($response->payment_url);
    }

    // 6. Implement: verify the payment on the IPN/callback route
    public function ipn_response(array $args = []): array
    {
        $payment_id = session()->get('yourgateway_payment_id');
        $order_id   = session()->get('yourgateway_order_id');
        session()->forget(['yourgateway_payment_id', 'yourgateway_order_id']);

        $payment = YourGatewaySdk::getPayment($payment_id);

        if ($payment->status === 'paid') {
            // verified_data() merges ['status' => 'complete'] with your array
            return $this->verified_data([
                'transaction_id' => $payment->id,
                'order_id'       => $order_id,
            ]);
        }

        return ['status' => 'failed', 'order_id' => $order_id];
    }

    // 7. Implement: currencies this gateway natively accepts
    public function supported_currency_list(): array
    {
        return ['USD', 'EUR', 'GBP']; // add all currencies the gateway accepts
    }

    // 8. Implement: return the currency that will actually be charged
    public function charge_currency(): string
    {
        return $this->getCurrency();
    }

    // 9. Implement: a lowercase slug for this gateway
    public function gateway_name(): string
    {
        return 'yourgateway';
    }
}

Step 2 — Register the Gateway in PaymentGatewayHelpers

Open src/Base/PaymentGatewayHelpers.php and add:

use Xgenious\Paymentgateway\Base\Gateways\YourGatewayPay;

// inside the class:
public function yourgateway(): YourGatewayPay
{
    return new YourGatewayPay();
}

The facade (XgPaymentGateway) proxies all calls to this class, so the method is immediately available:

XgPaymentGateway::yourgateway()

Step 3 — Add Credentials to the Config (optional)

If the gateway needs credentials from .env, add a block to config/paymentgateway.php:

'yourgateway' => [
    'api_key'    => env('YOURGATEWAY_API_KEY'),
    'secret_key' => env('YOURGATEWAY_SECRET_KEY'),
    'test_mode'  => env('YOURGATEWAY_TEST_MODE', true),
],

And add the corresponding keys to .env:

YOURGATEWAY_API_KEY=
YOURGATEWAY_SECRET_KEY=
YOURGATEWAY_TEST_MODE=true

Step 4 — Add a Blade View (if redirect-based)

Some gateways (e.g. Stripe, Razorpay) render a Blade view instead of a direct redirect. If your gateway needs one, create:

resources/views/yourgateway.blade.php

Return it from charge_customer:

public function charge_customer(array $args): mixed
{
    return view('paymentgateway::yourgateway', [
        'data' => [
            'api_key' => $this->getApiKey(),
            'amount'  => $this->charge_amount($args['amount']),
            // ...
        ]
    ]);
}

Step 5 — Add an IPN Route

In your application's routes/web.php (or the consuming app), register the callback route:

Route::get('/yourgateway-ipn', [PaymentLogController::class, 'yourgateway_ipn'])
    ->name('payment.yourgateway.ipn');

Then in the controller:

public function yourgateway_ipn()
{
    $yourgateway = XgPaymentGateway::yourgateway();
    $yourgateway->setApiKey(config('paymentgateway.yourgateway.api_key'));
    $yourgateway->setSecretKey(config('paymentgateway.yourgateway.secret_key'));
    $yourgateway->setEnv(config('paymentgateway.yourgateway.test_mode'));

    $response = $yourgateway->ipn_response();

    if ($response['status'] === 'complete') {
        // update order, mark as paid
    }
}

Available Traits

Trait Methods provided
PaymentEnvironment setEnv(bool), getEnv()
CurrencySupport setCurrency(string), getCurrency(), setExchangeRate(float), getExchangeRate()
ConvertUsdSupport get_amount_in_usd(float) — converts any amount to USD using the exchange rate
IndianCurrencySupport Converts to INR
IDRCurrencySupport Converts to IDR
NigeriaCurrencySupport Converts to NGN

verified_data() Return Format

ipn_response() must return an array. On success, use $this->verified_data([...]) which auto-merges status => complete:

// success
return $this->verified_data([
    'transaction_id' => 'txn_abc123',
    'order_id'       => 56,
]);
// result: ['status' => 'complete', 'transaction_id' => 'txn_abc123', 'order_id' => 56]

// failure
return ['status' => 'failed', 'order_id' => $order_id];

Recurring Payment Support (optional)

If the gateway supports subscriptions, implement the RecurringSupport interface:

use Xgenious\Paymentgateway\Base\RecurringSupport;

class YourGatewayPay extends PaymentGatewayBase implements RecurringSupport
{
    public function charge_customer_recurring(array $args): mixed { ... }
    public function ipn_response_recurring(array $args = []): array { ... }
}

Running Tests

composer test

Static Analysis

composer analysis

Contributing

See Contribution.md for guidelines.

License

MIT © XgeniousLLC

xgenious/paymentgateway 适用场景与选型建议

xgenious/paymentgateway 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 76 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 03 月 31 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「payment」 「paypal」 「stripe」 「mollie」 「laravel」 「razorpay」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 xgenious/paymentgateway 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 xgenious/paymentgateway 我们能提供哪些服务?
定制开发 / 二次开发

基于 xgenious/paymentgateway 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 76
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 38
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-03-31