承接 sudiptpa/omnipay-esewa 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

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

sudiptpa/omnipay-esewa

最新稳定版本:v3.0.1

Composer 安装命令:

composer require sudiptpa/omnipay-esewa

包简介

Framework-agnostic eSewa ePay v2 payment SDK for PHP.

README 文档

README

Framework-agnostic, zero-dependency PHP SDK for eSewa ePay v2, with an optional Omnipay v3 bridge.

CI Latest Release Packagist Version Packagist Downloads PHP Version License

Sponsor

If this package has been useful to you, GitHub Sponsors is a simple way to support ongoing maintenance, improvements, and future releases.

Public API

This package exposes two public namespaces:

  • Sujip\\Esewa
  • Omnipay\\Esewa

Highlights

  • checkout, callback, and transaction flows built around request and result models
  • typed value objects for amount, transaction UUID, product code, and reference ID
  • toArray() and fromArray() where they are useful
  • callback verification with explicit states: verified, invalid_signature, replayed
  • zero-dependency core with built-in CurlTransport
  • configurable retry policy and clock handling
  • replay protection backed by filesystem or PDO storage
  • optional PSR-18 transport support
  • optional Omnipay v3 bridge
  • PHP 8.2 to 8.5

Installation

composer require sudiptpa/omnipay-esewa

Optional PSR-18 usage:

composer require symfony/http-client nyholm/psr7

Documentation

Quick Start

<?php

declare(strict_types=1);

use Sujip\Esewa\Esewa;
use Sujip\Esewa\Domain\Checkout\CheckoutRequest;

$client = Esewa::make(
    merchantCode: 'EPAYTEST',
    secretKey: $_ENV['ESEWA_SECRET_KEY'],
    environment: 'uat',
);

$intent = $client->checkout()->createIntent(new CheckoutRequest(
    amount: '100',
    taxAmount: '0',
    serviceCharge: '0',
    deliveryCharge: '0',
    transactionUuid: 'TXN-1001',
    productCode: 'EPAYTEST',
    successUrl: 'https://merchant.example.com/esewa/success',
    failureUrl: 'https://merchant.example.com/esewa/failure',
));

The request constructor accepts strings for convenience. Internally, those values are normalized into value objects. If you want stricter typing in your own code, build the value objects directly:

use Sujip\Esewa\Domain\Checkout\CheckoutRequest;
use Sujip\Esewa\ValueObject\Amount;
use Sujip\Esewa\ValueObject\ProductCode;
use Sujip\Esewa\ValueObject\TransactionUuid;

$request = new CheckoutRequest(
    amount: Amount::fromString('100'),
    taxAmount: Amount::fromString('0'),
    serviceCharge: Amount::fromString('0'),
    deliveryCharge: Amount::fromString('0'),
    transactionUuid: TransactionUuid::fromString('TXN-1001'),
    productCode: ProductCode::fromString('EPAYTEST'),
    successUrl: 'https://merchant.example.com/esewa/success',
    failureUrl: 'https://merchant.example.com/esewa/failure',
);

Working With Models

The core models can be converted to arrays. That is mainly useful when you are crossing controller boundaries, queueing work, or saving fixtures for tests.

$payload = $request->toArray();
$restored = CheckoutRequest::fromArray($payload);

The client stays small. Most integrations only need three modules:

  • $client->checkout()
  • $client->callbacks()
  • $client->transactions()

Callback Verification

use Sujip\Esewa\Domain\Verification\CallbackPayload;
use Sujip\Esewa\Domain\Verification\VerificationExpectation;

$payload = CallbackPayload::fromArray([
    'data' => $_GET['data'] ?? '',
    'signature' => $_GET['signature'] ?? '',
]);

$result = $client->callbacks()->verifyCallback(
    $payload,
    new VerificationExpectation(
        totalAmount: '100.00',
        transactionUuid: 'TXN-1001',
        productCode: 'EPAYTEST',
    )
);

if ($result->state->value === 'replayed') {
    http_response_code(409);
    exit('Replay detected');
}

if (!$result->isSuccessful()) {
    http_response_code(400);
    exit('Invalid callback');
}

Do not treat the success redirect alone as proof of payment. Verify the callback on your backend and keep a status check as a fallback when something looks off.

Transaction Status

use Sujip\Esewa\Domain\Transaction\TransactionStatusRequest;

$status = $client->transactions()->fetchStatus(new TransactionStatusRequest(
    transactionUuid: 'TXN-1001',
    totalAmount: '100.00',
    productCode: 'EPAYTEST',
));

if ($status->isSuccessful()) {
    // mark paid
}

Production Notes

For live traffic, turn on replay protection and use persistent storage:

use Sujip\Esewa\Config\ClientOptions;
use Sujip\Esewa\Esewa;
use Sujip\Esewa\Infrastructure\Idempotency\FilesystemIdempotencyStore;

$client = Esewa::make(
    merchantCode: 'EPAYTEST',
    secretKey: $_ENV['ESEWA_SECRET_KEY'],
    environment: 'uat',
    options: new ClientOptions(
        preventCallbackReplay: true,
        idempotencyStore: new FilesystemIdempotencyStore(__DIR__ . '/storage/esewa-idempotency'),
    ),
);

Retry behavior is also configurable:

use Sujip\Esewa\Config\ClientOptions;
use Sujip\Esewa\Support\FixedDelayRetryPolicy;

$options = new ClientOptions(
    retryPolicy: new FixedDelayRetryPolicy(
        maxRetries: 3,
        delayUs: 250000,
    ),
);

Omnipay Bridge

use Omnipay\Esewa\SecureGateway;

$gateway = new SecureGateway();
$gateway->setMerchantCode('EPAYTEST');
$gateway->setSecretKey($_ENV['ESEWA_SECRET_KEY']);
$gateway->setProductCode('EPAYTEST');
$gateway->setTestMode(true);
$gateway->setReturnUrl('https://merchant.example.com/esewa/success');
$gateway->setFailureUrl('https://merchant.example.com/esewa/failure');

Supported bridge flows:

  • purchase()
  • completePurchase()
  • verifyPayment()

Development

composer test
composer stan
composer rector:check

统计信息

  • 总下载量: 4.09k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 7
  • 点击次数: 3
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 6
  • Watchers: 1
  • Forks: 3
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2019-03-16

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固