Skip to content

Latest commit

 

History

History
599 lines (443 loc) · 17.3 KB

README-ZH.md

File metadata and controls

599 lines (443 loc) · 17.3 KB

PHP 支付网关

Software License Latest Version on Packagist Total Downloads on Packagist StyleCI Maintainability Quality Score

这是一个用于整合支付网关的PHP包。这个包依赖 PHP 7.2+.

捐赠我 如果你喜欢这个包:sunglasses: :bowtie:

For Laravel integration you can use shetabit/payment package.

此软件包可用于多个驱动程序,如果在当前驱动程序列表中找不到驱动程序,则可以创建它们

目录

可用驱动列表

您可以通过pull requests 帮助我创建更多的网关

  • stripe
  • authorize
  • 2checkout
  • braintree
  • skrill
  • payU
  • amazon payments
  • wepay
  • payoneer
  • paysimple

如果找不到你需要的,您可以创建你自己的驱动,阅读创建自定义驱动部分,可以了解更多

安装

通过 Composer

$ composer require shetabit/multipay

配置

a. Copy config/payment.php and put it somewhere in your project. (you can also find it in vendor/shetabit/multipay/config/payment.php path).

b. 在配置文件中,您可以将 default设置项设置为你希望的付款方式。但也可以在运行时更改驱动。

选择要在应用程序中使用的网关。然后将其设为默认驱动程序,这样就不必在任何地方都指定它。但是,您也可以在一个项目中使用多个网关。

// Eg. if you want to use zarinpal.
'default' => 'zarinpal',

然后在驱动数组中填充该网关的凭据。

'drivers' => [
    'zarinpal' => [
        // Fill in the credentials here.
        'apiPurchaseUrl' => 'https://www.zarinpal.com/pg/rest/WebGate/PaymentRequest.json',
        'apiPaymentUrl' => 'https://www.zarinpal.com/pg/StartPay/',
        'apiVerificationUrl' => 'https://www.zarinpal.com/pg/rest/WebGate/PaymentVerification.json',
        'merchantId' => '',
        'callbackUrl' => 'http://yoursite.com/path/to',
        'description' => 'payment in '.config('app.name'),
    ],
    ...
]

c. Instantiate the Payment class and pass configs to it like the below:

    use Shetabit\Multipay\Payment

    // load the config file from your project
    $paymentConfig = require('path/to/payment.php');

    $payment = new Payment($paymentConfig);

如何使用

您的 Invoice 包含您的付款详细信息,因此我们首先将讨论 Invoice 类。

使用费用清单进行工作

在做任何事情之前,您需要使用 Invoice 类来创建费用清单。

像下面这样,在你的代码中使用费用清单:

// At the top of the file.
use Shetabit\Multipay\Invoice;
...

// Create new invoice.
$invoice = new Invoice;

// 设置清单金额.
$invoice->amount(1000);

// 给清单添加详情: 这里展示了四种语法.
// 1
$invoice->detail(['detailName' => 'your detail goes here']);
// 2 
$invoice->detail('detailName','your detail goes here');
// 3
$invoice->detail(['name1' => 'detail1','name2' => 'detail2']);
// 4
$invoice->detail('detailName1','your detail1 goes here')
        ->detail('detailName2','your detail2 goes here');

可用方法:

  • uuid: 设置一个清单的唯一id
  • getUuid: 获取清单的当前唯一id
  • detail: 给清单添加自定义信息
  • getDetails: 获取所有的详细信息
  • amount: 设置一个清单金额
  • getAmount: 获取清单金额
  • transactionId: 设置支付交易单号
  • getTransactionId: 获取支付交易单号
  • via: 设置我们用来支付清单的驱动
  • getDriver: 获取驱动

获取支付清单

为了支付清单,我们需要付款交易ID:

// At the top of the file.
use Shetabit\Multipay\Invoice;
use Shetabit\Multipay\Payment;
...

// load the config file from your project
$paymentConfig = require('path/to/payment.php');

$payment = new Payment($paymentConfig);


// Create new invoice.
$invoice = (new Invoice)->amount(1000);

// Purchase the given invoice.
$payment->purchase($invoice,function($driver, $transactionId) {
	// We can store $transactionId in database.
});

// Purchase method accepts a callback function.
$payment->purchase($invoice, function($driver, $transactionId) {
    // We can store $transactionId in database.
});

// You can specify callbackUrl
$payment->callbackUrl('http://yoursite.com/verify')->purchase(
    $invoice, 
    function($driver, $transactionId) {
    	// We can store $transactionId in database.
	}
);

支付

在获取支付单后,我们可以跳转到第三方支付机构的页面

// At the top of the file.
use Shetabit\Multipay\Invoice;
use Shetabit\Multipay\Payment;
...

// load the config file from your project
$paymentConfig = require('path/to/payment.php');

$payment = new Payment($paymentConfig);


// Create new invoice.
$invoice = (new Invoice)->amount(1000);
// Purchase and pay the given invoice.
// You should use return statement to redirect user to the bank page.
return $payment->purchase($invoice, function($driver, $transactionId) {
    // Store transactionId in database as we need it to verify payment in the future.
})->pay()->render();

// Do all things together in a single line.
return $payment->purchase(
    (new Invoice)->amount(1000), 
    function($driver, $transactionId) {
        // 把交易ID保存到数据库.
        // 在接下来的付款中,我们需要验证交易ID
	}
})->pay()->render();

// Retrieve json format of Redirection (in this case you can handle redirection to bank gateway)
return $payment->purchase(
    (new Invoice)->amount(1000), 
    function($driver, $transactionId) {
        // 把交易ID保存到数据库.
        // 在接下来的付款中,我们需要验证交易ID
	}
)->pay()->toJson();

验证付款

当用户完成付款后,支付机构会将其重定向到您的网站,然后您需要验证您的付款,以确保清单支付

// At the top of the file.
use Shetabit\Multipay\Payment;
use Shetabit\Multipay\Exceptions\InvalidPaymentException;
...

// load the config file from your project
$paymentConfig = require('path/to/payment.php');

$payment = new Payment($paymentConfig);


// 您需要验证支付机构的回传数据,以确保付款成功
// 我们需要使用交易ID来验证
// 使用交易金额来验证,也是一个很好的方法
try {
	$receipt = $payment->amount(1000)->transactionId($transaction_id)->verify();

    // You can show payment referenceId to the user.
    echo $receipt->getReferenceId();

    ...
} catch (InvalidPaymentException $exception) {
    /**
    	如果未验证付款,则会引发异常。
        我们可以抓住异常处理无效付款。
        getMessage方法,返回可在用户界面中使用的适当消息。
    **/
    echo $exception->getMessage();
}

有用的方法

  • callbackUrl: 使用它可以在运行时改变回调地址.
    // At the top of the file.
    use Shetabit\Multipay\Invoice;
    use Shetabit\Multipay\Payment;
    ...
      
    // load the config file from your project
    $paymentConfig = require('path/to/payment.php');
    
    $payment = new Payment($paymentConfig);
    
    
    // Create new invoice.
    $invoice = (new Invoice)->amount(1000);
    
    // Purchase the given invoice.
    Payment::callbackUrl($url)->purchase(
        $invoice, 
        function($driver, $transactionId) {
        // We can store $transactionId in database.
    	}
    );
  • amount: 你可以设置一个清单的金额
    // At the top of the file.
    use Shetabit\Multipay\Invoice;
    use Shetabit\Multipay\Payment;
    ...
    
    // load the config file from your project
    $paymentConfig = require('path/to/payment.php');
    
    $payment = new Payment($paymentConfig);
    
    
    // Purchase (we set invoice to null).
    $payment->callbackUrl($url)->amount(1000)->purchase(
        null, 
        function($driver, $transactionId) {
        // We can store $transactionId in database.
    	}
    );
  • via: 在运行中更改支付方式
    // At the top of the file.
    use Shetabit\Multipay\Invoice;
    use Shetabit\Multipay\Payment;
    ...
    
    // load the config file from your project
    $paymentConfig = require('path/to/payment.php');
    
    $payment = new Payment($paymentConfig);
    
    
    // Create new invoice.
    $invoice = (new Invoice)->amount(1000);
    
    // Purchase the given invoice.
    $payment->via('driverName')->purchase(
        $invoice, 
        function($driver, $transactionId) {
        // We can store $transactionId in database.
    	}
    );
  • config: 在运行中更改驱动的配置信息
    // At the top of the file.
    use Shetabit\Multipay\Invoice;
    use Shetabit\Multipay\Payment;
    ...
    
    // load the config file from your project
    $paymentConfig = require('path/to/payment.php');
    
    $payment = new Payment($paymentConfig);
    
    
    // Create new invoice.
    $invoice = (new Invoice)->amount(1000);
    
    // Purchase the given invoice with custom driver configs.
    $payment->config('mechandId', 'your mechand id')->purchase(
        $invoice,
        function($driver, $transactionId) {
        // We can store $transactionId in database.
    	}
    );
    
    // Also we can change multiple configs at the same time.
    $payment->config(['key1' => 'value1', 'key2' => 'value2'])->purchase(
        $invoice,
        function($driver, $transactionId) {
        // We can store $transactionId in database.
    	}
    );

创建自定义驱动:

首先必须在drivers数组中添加驱动程序的名称,还可以指定所需的任何配置参数。

'drivers' => [
    'zarinpal' => [...],
    'my_driver' => [
        ... // Your Config Params here.
    ]
]

现在您必须创建一个将用于支付清单的驱动程序映射类。 在你的驱动中,你必须继承 Shetabit\Multipay\Abstracts\Driver.这个类

例如,你创建了这样一个类: App\Packages\PaymentDriver\MyDriver

namespace App\Packages\PaymentDriver;

use Shetabit\Multipay\Abstracts\Driver;
use Shetabit\Multipay\Exceptions\InvalidPaymentException;
use Shetabit\Multipay\{Contracts\ReceiptInterface, Invoice, RedirectionForm, Receipt};

class MyDriver extends Driver
{
    protected $invoice; // Invoice.

    protected $settings; // Driver settings.

    public function __construct(Invoice $invoice, $settings)
    {
        $this->invoice($invoice); // Set the invoice.
        $this->settings = (object) $settings; // Set settings.
    }

    // Purchase the invoice, save its transactionId and finaly return it.
    public function purchase() {
        // Request for a payment transaction id.
        ...
            
        $this->invoice->transactionId($transId);
        
        return $transId;
    }
    
    // Redirect into bank using transactionId, to complete the payment.
    public function pay() : RedirectionForm {
        // It is better to set bankApiUrl in config/payment.php and retrieve it here:
        $bankUrl = $this->settings->bankApiUrl; // bankApiUrl is the config name.

        // Prepare payment url.
        $payUrl = $bankUrl.$this->invoice->getTransactionId();

        // Redirect to the bank.
        $url = $payUrl;
        $inputs = [];
        $method = 'GET';

        return $this->redirectWithForm($url, $inputs, $method);
    }
    
    // Verify the payment (we must verify to ensure that user has paid the invoice).
    public function verify(): ReceiptInterface {
        $verifyPayment = $this->settings->verifyApiUrl;
        
        $verifyUrl = $verifyPayment.$this->invoice->getTransactionId();
        
        ...
        
        /**
			Then we send a request to $verifyUrl and if payment is not valid we throw an InvalidPaymentException with a suitable message.
        **/
        throw new InvalidPaymentException('a suitable message');
        
        /**
        	We create a receipt for this payment if everything goes normally.
        **/
        return new Receipt('driverName', 'payment_receipt_number');
    }
}

创建该类后,必须在 payment.php 配置文件的 map 部分中指定它。

'map' => [
    ...
    'my_driver' => App\Packages\PaymentDriver\MyDriver::class,
]

Note: 必须确保 map 数组的键与 drivers 数组的键相同。

事件:

Notice 1: event listeners will be registered globaly for all payments.

Notice 2: if you want your listeners work correctly, you must subcribe them before the target event dispatches.

Its better to subcribe events in your app's entry point or main service provider, so events will be subcribed before any events dispatches.


You can listen for 3 events:

  1. purchase
  2. pay
  3. verify.
  • purchase: Occurs when an invoice is purchased (after purchasing invoice is done successfully).
// add purchase event listener
Payment::addPurchaseListener(function($driver, $invoice) {
    echo $driver;
    echo $invoice;
});
  • pay: Occurs when an invoice is prepared to pay.
// add pay event listener
Payment::addPayListener(function($driver, $invoice) {
    echo 'first listener';
});

// we can add multiple listeners
Payment::addPayListener(function($driver, $invoice) {
    echo 'second listener';
});
  • verify: Occurs when an invoice is verified successfully.
// we can add multiple listeners and also remove them!!!

$firstListener = function($driver, $invoice) {
    echo 'first listener';
};

$secondListener = function($driver, $invoice) {
    echo 'second listener';
};

Payment::addVerifyListener($firstListener);
Payment::addVerifyListener($secondListener);

// remove first listener
Payment::removeVerifyListener($firstListener);

// if we call remove listener without any arguments, it will remove all listeners
Payment::removeVerifyListener(); // remove all verify listeners :D

Change log

请查看 CHANGELOG 来获取更多关于版本更新的信息

贡献

请查看 CONTRIBUTINGCONDUCT 获取更多详细信息

安全

如果您发现任何与安全相关的问题,请发送电子邮件至khanzadimahdi@gmail.com,而不要使用issue。

信誉

License

The MIT License (MIT). Please see License File for more information.