romero / multipay
PHP支付网关集成包
Requires
- php: >=8.1
- chillerlan/php-cache: dev-main
- guzzlehttp/guzzle: >=6.2
- nesbot/carbon: ^1.39|^2.0
- ramsey/uuid: ^3.7|^3.8|^3.9|^4.0
Requires (Dev)
- phpunit/phpunit: ^8.0|^9.0
- squizlabs/php_codesniffer: ^3.5
This package is auto-updated.
Last update: 2024-09-22 20:51:15 UTC
README
PHP支付网关
这是一个用于支付网关集成的PHP包。此包支持PHP 7.2+
。
如果你喜欢这个包,请支持我 😎
对于Laravel集成,你可以使用shetabit/payment包。
此包支持多个驱动程序,如果当前驱动程序列表(以下列表)中找不到,你可以创建自定义驱动程序。
目录列表
可用驱动程序列表
- asanpardakht ✔️
- aqayepardakht ✔️
- atipay ✔️
- azkiVam (分期付款) ✔️
- behpardakht (mellat) ✔️
- bitpay ✔️
- digipay ✔️
- etebarino (分期付款) ✔️
- fanavacard ✔️
- idpay ✔️
- irankish ✔️
- local ✔️
- jibit ✔️
- nextpay ✔️
- omidpay ✔️
- parsian ✔️
- pasargad ✔️
- payir ✔️
- payfa ✔️
- paypal (将在下一个版本中添加)
- payping ✔️
- paystar ✔️
- poolam ✔️
- rayanpay ✔️
- sadad (melli) ✔️
- saman ✔️
- sep (saman电子支付) Keshavarzi & Saderat ✔️
- sepehr (saderat) ✔️
- sepordeh ✔️
- sizpay ✔️
- toman ✔️
- vandar ✔️
- walleta(分期付款) ✔️
- yekpay ✔️
- zarinpal ✔️
- zibal ✔️
- 其他正在路上。
请通过创建pull requests
来帮助我添加以下网关:
- stripe
- authorize
- 2checkout
- braintree
- skrill
- payU
- amazon payments
- wepay
- payoneer
- paysimple
如果列表中没有,您可以创建自己的自定义驱动程序,请阅读
创建自定义驱动程序
部分。
安装
通过Composer
$ composer require shetabit/multipay
配置
a. 将config/payment.php
复制到项目中的某个位置。(您也可以在vendor/shetabit/multipay/config/payment.php
路径中找到它)。
b. 在配置文件中,您可以设置用于所有支付的默认驱动程序,并且也可以在运行时更改驱动程序。
选择您在应用程序中想要使用的网关。然后将其作为默认驱动程序,这样您就不必在所有地方指定它。但是,您也可以在项目中使用多个网关。
// 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. 实例化Payment
类,并像下面一样传递配置
use Romero\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 Romero\Multipay\Invoice; ... // Create new invoice. $invoice = new Invoice; // Set invoice amount. $invoice->amount(1000); // Add invoice details: There are 4 syntax available for this. // 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
:设置发票的唯一IDgetUuid
:检索发票当前的唯一IDdetail
:将一些自定义详情附加到发票上getDetails
:检索所有自定义详情amount
:设置发票金额getAmount
:检索发票金额transactionId
:设置发票支付事务IDgetTransactionId
:检索支付事务IDvia
:设置我们用来支付发票的驱动程序getDriver
:检索驱动程序
购买发票
为了支付发票,我们需要支付事务ID。我们购买发票以检索事务ID
// At the top of the file. use Romero\Multipay\Invoice; use Romero\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 Romero\Multipay\Invoice; use Romero\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) { // Store transactionId in database. // We need the transactionId to verify payment in the future. } )->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) { // Store transactionId in database. // We need the transactionId to verify payment in the future. } )->pay()->toJson();
验证支付
当用户完成支付后,银行将他们重定向到您的网站,然后您需要强有力地验证您的支付,以确保invoice
已经被支付。
// At the top of the file. use Romero\Multipay\Payment; use Romero\Multipay\Exceptions\InvalidPaymentException; ... // load the config file from your project $paymentConfig = require('path/to/payment.php'); $payment = new Payment($paymentConfig); // You need to verify the payment to ensure the invoice has been paid successfully. // We use transaction id to verify payments // It is a good practice to add invoice amount as well. try { $receipt = $payment->amount(1000)->transactionId($transaction_id)->verify(); // You can show payment referenceId to the user. echo $receipt->getReferenceId(); ... } catch (InvalidPaymentException $exception) { /** when payment is not verified, it will throw an exception. We can catch the exception to handle invalid payments. getMessage method, returns a suitable message that can be used in user interface. **/ echo $exception->getMessage(); }
有用方法
-
callbackUrl
:可以用于在运行时更改回调URL。// At the top of the file. use Romero\Multipay\Invoice; use Romero\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 Romero\Multipay\Invoice; use Romero\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 Romero\Multipay\Invoice; use Romero\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 Romero\Multipay\Invoice; use Romero\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. } );
-
custom fields
:使用网关的自定义字段(并非所有网关都支持此功能)SEP网关支持多达4个自定义字段,并且您可以设置值长达50个字符。这些自定义字段仅在用户面板中查看报告时显示。// At the top of the file. use Romero\Multipay\Invoice; ... // Create new invoice. $invoice = (new Invoice)->amount(1000); // Use invoice bag to store custom field values. $invoice->detail([ 'ResNum1' => $order->orderId, 'ResNum2' => $customer->verifiedCode, 'ResNum3' => $someValue, 'ResNum4' => $someOtherValue, ]);
创建自定义驱动程序
首先,您必须在驱动程序数组中添加您驱动程序的名字,并且您可以指定任何您想要的配置参数。
'drivers' => [ 'zarinpal' => [...], 'my_driver' => [ ... // Your Config Params here. ] ]
现在,您必须创建一个用于支付发票的Driver Map类。在您的驱动程序中,您只需扩展Romero\Multipay\Abstracts\Driver
。
例如,您创建了一个类:App\Packages\Multipay\Driver\MyDriver
。
namespace App\Packages\Multipay\Driver; use Romero\Multipay\Abstracts\Driver; use Romero\Multipay\Exceptions\InvalidPaymentException; use Romero\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\Multipay\Driver\MyDriver::class, ]
注意:您必须确保map
数组中的键与drivers
数组中的键相同。
事件
注意 1:将为所有付款全局注册事件监听器。
注意 2:为了确保您的监听器正常工作,您必须在目标事件分发之前将它们订阅。
最好在您的应用程序的入口点或主服务提供商中订阅事件,这样事件就会在事件分发之前订阅。
您可以监听3个事件
- 购买
- 付款
- 验证.
- 购买:当发票被购买时发生(购买发票成功完成后)。
// add purchase event listener Payment::addPurchaseListener(function($driver, $invoice) { echo $driver; echo $invoice; });
- 付款:当发票准备付款时发生。
// 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'; });
- 验证:当发票验证成功时发生。
// 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
本地驱动器
Local
驱动器可以模拟真实网关的支付流程,用于开发目的。
可以像调用其他驱动器一样启动付款。
$invoice = (new Invoice)->amount(10000); $payment->via('local')->purchase($invoice, function($driver, $transactionId) { // a fake transaction ID is generated and returned. })->pay()->render();
调用render()
方法将渲染一个包含接受和取消按钮的HTML
表单,模拟真实支付网关的相应操作,并重定向到指定的回调URL。返回的查询URL中始终会包含transactionId
参数。
收到回调请求后可以验证付款。
$receipt = $payment->via('local')->verify();
在付款成功的情况下,$receipt
将包含以下参数
[ 'orderId' => // fake order number 'traceNo' => // fake trace number (this should be stored in databse) 'referenceNo' => // generated transaction ID in `purchase` method callback 'cardNo' => // fake last four digits of card ]
在付款取消的情况下,将抛出PurchaseFailedException
以模拟网关验证失败。
可以通过Invoice
详细包配置驱动器功能。
$invoice->detail([ // setting this value will cause `purchase` method to throw an `PurchaseFailedException` // to simulate when a gateway can not initialize the payment. 'failedPurchase' => 'custom message to decribe the error', // Setting this parameter will be shown in payment form. 'orderId' => 4444, ]);
可以通过在payment.php
文件中的local
驱动器的配置参数中自定义,来定制支付表单的外观。
'local' => [ // default callback url of the driver 'callbackUrl' => '/callback', // main title of the form 'title' => 'Test gateway', // a description to show under the title for more clarification 'description' => 'This gateway is for using in development environments only.', // custom label to show as order No. 'orderLabel' => 'Order No.', // custom label to show as payable amount 'amountLabel' => 'Payable amount', // custom label of successful payment button 'payButton' => 'Successful Payment', // custom label of cancel payment button 'cancelButton' => 'Cancel Payment', ],
变更日志
有关最近更改的更多信息,请参阅变更日志。
贡献
安全
如果您发现任何安全相关的问题,请通过电子邮件khanzadimahdi@gmail.com联系,而不是使用问题跟踪器。
鸣谢
许可
MIT许可证(MIT)。有关更多信息,请参阅许可证文件。