如何用PHP接入越南支付网关?

使用PHP接入越南支付网关的指南

要使用PHP接入越南支付网关,您需要遵循以下步骤。我将以几个流行的越南支付网关为例进行说明。

常见越南支付网关选择

  1. VNPay – 最受欢迎的本地支付解决方案之一
  2. Momo – 移动钱包支付
  3. ZaloPay – 另一个流行的电子钱包
  4. OnePay – Visa/MasterCard处理商

VNPay集成示例

1. 准备工作

2. PHP集成代码示例

<?php
// config.php - VNPay配置参数
$vnp_Url = "https://sandbox.vnpayment.vn/paymentv2/vpcpay.html";
$vnp_Returnurl = "https://yourdomain.com/return_url.php"; //回调URL
$vnp_TmnCode = "YOUR_MERCHANT_CODE"; //商户号
$secretKey = "YOUR_SECRET_KEY"; //安全密钥

// vnpay_create_payment.php -创建付款请求
function createVNPayPayment($orderId, $amount, $orderInfo) {
global $vnp_Url, $vnp_Returnurl, $vnp_TmnCode, $secretKey;

date_default_timezone_set('Asia/Ho_Chi_Minh');

//准备参数数组
$inputData = array(
"version" => "2",
"command" => "pay",
'merchant' => 'VNPAY',
'tmn_code' => trim($tmnCode),
'create_date' => date('YmdHis'),
'expire_date' => date('YmdHis', strtotime('+15 minutes')),

//订单信息
'order_id' => time(),

//金额(单位为VND)
'amount'=> intval(str_replace(',','',$amount))*100,

//订单描述
'order_desc'=> urlencode($orderInfo),

return_url=> urlencode($return_url),

ip_address=> $_SERVER['REMOTE_ADDR'],

currency=>"VND",

locale=> ($lang == "") ? vn : en,

bank_code=> "",
);

ksort($inputData);

query="";
foreach ($inputData as key value){
if(substr(key0)=="_") continue;
if(!empty(query)) query.= &".key."=".$value; else query=key."=".$value;}

secureHash=hash("sha256", secret_key.query);

inputData["secure_hash"]=$secureHash;

paymentUrl=vpn_URL ."?".http_build_query(input_data);

header("Location: ".payment_url); exit();}

Momo Wallet集成示例

<?php 
// momo_config.php
define("PARTNER_CODE", "");//Your partner code from MoMo");
define("ACCESS_KEY",""); ///Your access key from MoMo");
define("SECRET_KEY",""); ///Your secret key from MoMo");

function execPostRequest(url data){
ch curl_init();
curl_setopt(ch CURLOPT_URL url);
curl_setopt(ch CURLOPT_POST true);
curl_setopt(ch CURLOPT_POSTFIELDS data);
curl_setopt(ch CURLOPT_USERAGENT $_SERVER['HTTP_USER_AGENT']);
curl_setopt(ch CURLOPT_RETURNTRANSFER true);

result=curl_exec ch );curl_close ch ); return result;}

function createMomoPayment(orderId amount orderInfo callbackUrl redirectUrl){
endpoint ="https://test-payment.momo.vn/gw_payment/transactionProcessor";

requestId time()."";//unique id for each request

rawHash ="partnerCode=" PARTNER CODE.
&accessKey ACCESS KEY.
&requestId request Id.
&amount amount.
&orderId order Id .
order info .
return Url callback Url .
notify Url callback Url .extra Data "";

signature hash hmac sha256 raw Hash SECRET KEY));
data array(
partner Code PARTNER CODE ,
access Key ACCESS KEY ,
request Id request Id ,
amount amount ,
order Id order ID ,

Order Info urldecode(order Info ),

Return URL redirect URL ,

Notify URL call back URl ,

extra Data "",

Request Type capture MO wallet ",

Signature signature ) ;

JSON encode(data));

response exec Post Request(endpoint json encodedata));

json decode(response true);


if isset(result pay UrL )) header Location result pay UrL ]); else echo Error creating payment ;}?>

Zalo Pay集成示例(类似结构)

 
class ZalopayHelper {

const APP_ID your app id ;
const KEY1 your key1 ;
const EMBED DATA [" merchantinfo"=> embeddata json encode([" merchant name"=> Your Store Name ])];

public static function CreateOrder( string description long price string callback url ){
date default timezone set Asia Ho Chi Minh );

timestamp round(microtime(true)*1000);

params [
appid self APP ID,
apptransid date(Ymd)._. timestamp,# format yyMMdd timestamp e.g21092740765200

appuser Zalo Pay Demo m desc description,

amoun tprice ,

item JSON encode([]),

bankcode zalopayapp ,

callbackurl call back ur l ];

Mac=self Compute Mac(params);

params[ mac]=Mac;

response Http Helper post https sb openapi zalopay vn /vp/create params );

return json decode response body ) ;

}

private static function Compute Mac(array params ):string {

orderedParams [];

foreach ([ appid , apptransid , appuser amoun t apptime emb edda ta item ]as param){

if isset params param]) ordered Params[]=$param.'='.$params[$param];}

message implode(& ordered Params );

return hash hmac sha256 message self::KEY one false );}}

One Pay国际卡处理(适用于信用卡)

 
class One PayInternational {

private static endpoint sandbox onep ay international com api/v two /processor ;

public static process Payment card Number expiry Month expiry Year cv vAmount currency Description ){
date default timezone set Asia Ho Chi Minh );
nonce bin hex random bytes sixteen ));

post Fields [
number card Number ],
exp month expiry Month ],
exp year expiry Year ],cvv cv v],
currency str toupper currency ),
amoun tround float val Amount *100 ),# in cents/pence/etc.

description substr Description fifty ),
three DSecure false ];

json payload json encode post fields base sixty four encode nonce.json payload));

signature base sixty four encode hash hmac sha two five six nonce.payload YOUR API SECRE Ttrue));

headers [

Content Type application/json',

Authorization Bearer.YOUR API TOKEN ,

Signature.signature ];

ch init();

set opt ch,CUR LOP TSSL VERIFYPEERfalse);

set opt ch,CUR LOP THEADE R headers );

set optch CUR LOP POSTtrue);

set optch CUR LOP POS TFIELDS payload );

set optch CUR LOP RET UR NTR ANSFE Rtrue);


exec curlexe cch close (ch return response ;}}

?>"

重要提示:

所有上述代码仅为基本框架,实际实现时需注意:
安全性措施如输入验证、错误处理和日志记录必须到位。
生产环境应使用HTTPS并存储敏感数据在安全位置。
根据最新API文档调整参数名称和值格式。

建议先在各支付的沙盒环境中测试您的实现。

继续PHP接入越南支付网关的详细指南

下面我将更深入地介绍如何完善支付集成,包括回调处理、安全措施和常见问题的解决方案。

1. VNPay回调处理实现

当用户完成支付后,VNPay会通过两种方式通知你的系统:

  • 浏览器重定向(return_url)
  • 服务器异步通知(IPN – Instant Payment Notification)

return_url.php示例代码

<?php
// config.php
require_once('config.php');

// 获取所有GET参数
$vnp_Params = $_GET;
$secureHash = $vnp_Params['vnp_SecureHash'];
unset($vnp_Params['vnp_SecureHash']);

// 按字母顺序排序参数
ksort($vnp_Params);

// 生成验证用的hash值
$hashData = "";
foreach ($vnp_Params as $key => $value) {
if (substr($key, 0, 4) == "vnp_") {
$hashData .= urlencode($key) . "=" . urlencode($value) . "&";
}
}
$hashData = rtrim($hashData, '&');

$secureSecret = $secretKey; // from config.php
$mySecureHash = hash_hmac('sha512', $hashData, $secureSecret);

if ($mySecureHash === $secureHash) {
if ($_GET['vnP_ResponseCode'] == '00') {
// 付款成功逻辑

/*
* TODO:
* - 更新订单状态为已付款
* - 记录交易信息到数据库
* - vnP_TxnRef是您的订单ID(您最初传给VNPay的)
*/

echo "Payment Success for order: ".$_GET['vnP_TxnRef'];
} else {
// Payment failed or cancelled by user

/*
* TODO:
* - Update order status to failed/cancelled in your database
*/

echo "Payment Failed/Cancelled";
}
} else {
die("Invalid signature");
}

IPN处理脚本 (ipn_listener.php)

<?php  
require_once('config.php');

file put contents ('ipn log.txt', print r($_POST true)."\n", FILE APPEND );

if (!empty($_POST)) {
input Data=$ POST;
secure Hash=input Data ['vn p Secure Hash'];
unset(input Data ['vn p Secure Hash']);

ksort(input Data);

i=0;

hash Data="";

foreach (input Data as key value){
if substr(key04)=="vn p"){
if strlen(hash Dat a)>0){
hash Dat a.='&'.url encode(key).'='.url encode(value);
}else{
hash Dat a.=url encode(key).'='.url encode(value);
}
}
}

check Sum=hash hmac sha512(h ash Da ta secret Key );

if check Sum== secure Has h){
transaction Id=input Da ta ['vp Txn Ref'];
response Code=input Da ta ['vp Response Co de'];

/* TODO:
1 Validate the amount matches your expected amount
2 Check this is not duplicate notification
3 Update your database accordingly */

switch(response Co de){ case"00": /* SUCCESS */ break ; default : /* FAILURE */ break ; }}else{ http response code(403);//Forbidden exit();}?>

MoMo钱包高级集成技巧

Webhook验证示例

 
function verify MomoWeb hook(Request request ){
partner Code request input('partner Code');
access Key request input('access Key');
request Id time()."";//should match original
order Id request input('orderId');

amount req uest->input amoun t));
order Info urldecode(req uest->input desc )));
response Time req uest->input resp onse Time )));
message req uest->input mes sage )));
trans Id req uest->input transId )));
error Cod e re quest ->in put errorCode )) ? :0;

extra D ata "";//custom data you passed initially now returned back unchanged
raw H ash ="partnerCode={ partnerCo de}&accessKey={ accessKe y}&requestId={ reques tI d}&amount={ amo unt}&orderId={ ord erI d}"."&orderInfo={ orde rIn fo}&responseTime={ res pon seT ime}{ ext raD ata}";

signatureFromMomo=req est >i nput sig nature );

ourSignature=ha sh hm ac sha256 rawH ash SECRET KEY );

if our Signature!= signature From Momo || errorC ode !=0){
log info ("Invalid MoMo webhook received".json encodereq est all()));
abort(400,"Bad Request");}

/* Process successful payment here */

return response json success truemessage OK ]200 headers Content Type application/json ];}

Zalo Pay退款流程实现

 
class ZalopayService{

const REFUND ENDPOINT https sb openapi zalopay vn /vp/refund ;

public static function process Refund(string zp Trans Token long refund Amount string description ){
timestamp round microtime true)*1000 );

params [
appid self APP ID,
zptransid zpTransToken ,
amoun t refundAmount ,
description substr description fifty ),
timestamp timestamp ];

Mac=self Compute Mac params );

params mac]=Mac;

response Http Helper post self REFUND ENDPOINT params );

result json decode response body true );

if isset result return code])&& result return code]==1){
/*
TODO:
Update your database to reflect refund status*/
return true;}else{
Log error ("ZaloPay refund failed".print r(resulttrue));
throw new Exception Failed to process refund with Zalo Pay.);}}

One Pay国际卡支付的3D Secure集成

对于需要3D认证的交易:


class ThreeDSecureHandler {

public static function initiateThreeDSecure(array card Details float amount string currency ){
one pay Client new One PayInternational();

auth Response one pay Client create Auth Request card Details amount currency three DSEnabled=>true]);

three Ds Method Url auth Response three ds method url ??null;

three Ds Server Trans ID auth Response three ds server trans id ??null;

session put current payment session [ ...cardDetails ,... authResponse ]);

redirect Url route checkout.threeds challenge name ]);

return view checkout.threeds initiate compact redirectUrl threeDsMethodUrl threeDsServerTransId amount currency cardDetails lastFour digits]));

}

public static function handle Challenge Completion(Request req ){
session Get current payment session ;

one pay Client new OnePayInternational();

finalize Result one payClient complete Three DS Auth session get threeds server trans id ],req all());

/* Verify MAC/signature etc.*/

switch finalize Result status]){
case succeeded :
Order Service mark Paid session get order id ]);
break;
default:
Order Service mark Failed(session get order id ]);
throw new PaymentFailedException();
}}}

Security Best Practices安全最佳实践

Essential Security Measures:

1.Always validate callbacks: Never trust incoming requests without verifying signatures.

2.Use HTTPS everywhere: Especially for callback URLs and when transmitting sensitive data.

3.Implement CSRF protection: On pages initiating payments.

4.Sanitize all inputs: Prevent XSS/SQL injection attacks.

5.Log important events: But don’t log full card details or sensitive tokens.

6.Store minimal data: Don’t store PAN/CVV after processing completes successfully.

7.Use up-to-date TLS versions(v1.2+).

8.Regularly rotate API keys/secrets especially after staff changes .

9.Monitor for suspicious activity like multiple failed attempts .

10.Keep PHP and dependencies patched against known vulnerabilities .

Troubleshooting Common Issues常见问题排查

Issue现象 Possible Causes可能原因 Solutions解决方案
Invalid/Missing Signature签名错误 Wrong hashing algorithm算法不一致
Parameter ordering issue参数顺序错误
Encoding problem编码问题
Double-check gateway docs文档确认
Ensure exact same parameter ordering严格按字母序
Test with their sample values使用测试数据验证
Callbacks not received未收到回调 Firewall blocking防火墙拦截
URL incorrect地址错误
Temporary gateway outage服务暂时不可用
Whitelist gateway IPs白名单设置
Verify URL in merchant dashboard商户后台检查
Contact support联系支持团队
Payments stuck pending状态一直待处理 Asynchronous processing延迟处理
Settlement batch timing结算批次时间差
Suspected fraud suspected欺诈审查中 Wait合理等待时间后查询交易状态或联系客服

Remember that each Vietnamese payment provider may have specific requirements so always refer to their latest official documentation before going live with any integration.