菲律宾本地支付 · 原生通道直连

用PHP/Python对接GCash或Maya支付接口

对接GCash和Maya支付接口指南

GCash支付接口对接

PHP实现方式

<?php
// GCash API配置
$gcash_api_key = 'YOUR_GCASH_API_KEY';
$gcash_secret = 'YOUR_GCASH_SECRET';
$gcash_base_url = 'https://api.gcash.com';

// 创建支付请求
function createGcashPayment($amount, $reference_id, $callback_url) {
global $gcash_api_key, $gcash_secret, $gcash_base_url;

$endpoint = '/payments/v1/payments';
$timestamp = time();

// 构建请求数据
$data = [
'amount' => number_format($amount, 2),
'currency' => 'PHP',
'payment_method' => ['type' => 'GCASH'],
'reference_id' => $reference_id,
'redirect_urls' => [
'success' => "$callback_url?status=success",
'failure' => "$callback_url?status=failure",
"cancel" => "$callback_url?status=cancel"
]
];

// 生成签名
$signature_data = json_encode($data) . "|" . strval($timestamp);
$signature = hash_hmac('sha256', utf8_encode($signature_data), utf8_encode($gcash_secret));

// HTTP请求头设置
return sendRequest(
method: "POST",
url: "$baseUrl/$endpoint",
headers: [
"Content-Type: application/json",
"X-GCash-Timestamp: {$timestamp}",
"Authorization: Bearer {$apiKey}",
"X-GCash-Signature: {$signature}"
],
data:$data);
}

function sendRequest(string method , string url , array headers , array data):array{
/* ... */
}
?>

Python实现方式

import requests
import hashlib
import hmac
import time

class GcashPayment:

def __init__(self):
self.api_key="your_gcash_api_key"
self.secret="your_gcash_secret".encode()
self.baseurl="https://api.gcash.com"

def create_payment(self amount reference callback):
"""创建GCASH付款"""
endpoint="/payments/v1/payments"
current_time=str(int(time.time()))
payload={
"amount":f"{float(amount):.2f}"
"currency":"PHP"
"payment_method":{"type":"GCASH"}
...
}
#生成签名
signdata=(json.dumps(payload)+f"|{current_time}").encode()
sign=hmac.new(self.secrect signdata hashlib.sha256).hexdigest()

headers={
...
}

response=requests.post(f"{baseurl}{endpoint}" json=payload headers=headers)
return response.json() if response.ok else None

Maya支付接口对接(Maya Checkout)

PHP实现方式

<?php 

class MayaPayments {

private string apiKey;
private string secret;

public function __construct(string key string secret){
$this->apiKey=$key;
$this->secret=$secret;
}

public function checkout(float amount string refId callable successHandler){
/*准备基本参数*/
$nonce=microtime(true)*10000;

/*构造签名字符串*/
$message=sprintf("%s:%s:%s:%d",strtoupper("POST"),"/checkout/v1/checkouts",...);

/*计算HMAC-SHA256签名*/
hash_hmac("sha256",utf8_encode(message),utf8_encode(this->secret));

/*发送API请求*/
curl_setopt_array(ch,[...]);

if(curl_errno(ch)){
throw new RuntimeException(curl_error(ch));
}

return json_decode(response false);
}
}
?>

Python实现方式

from datetime import datetime as dt  
from base64 import b64encode as enc64

class MayaClient:

CHECKOUT_URL='https://pg-sandbox.paymaya.com'

@staticmethod
def generate_signature(request_path request_body secret):

nowdt=dt.utcnow().strftime('%a %d %b %Y %H:%M:%S GMT')

string_to_sign=f"""POST {request_path}\n{nowdt}\n{request_body}"""

return enc64(hmac.new(key.encode(),msg.encode(),digestmod='sha1').digest()).decode()

async def create_checkout(total_amount items redirect_success redirect_fail):

body={"totalAmount":{"value":total_amount,...}}

path='/checkout/v1/checkouts'
auth=self.generate_signature(path body this.seckey)

resp=aiohttp.post(f'{URL}{path}' data=dumps(body) headers={...})

if resp.status!=201:
raise Exception(...)

return await resp.json()

Webhook处理示例(PHP+Python通用逻辑)

接收通知 → [验证签名] → [检查金额状态] → [更新订单] → [返回200 OK]
| |
V V
HMAC校验 数据库查询匹配

关键注意事项:

  • 沙箱环境:先使用测试API密钥开发调试,不要直接上生产环境。
  • 安全存储:API密钥和秘钥必须安全存储,推荐使用环境变量或加密存储。

继续深入GCash和Maya支付接口对接

GCash Webhook处理最佳实践

PHP实现方案

<?php
// GCash Webhook处理器
class GcashWebhookHandler {
const WEBHOOK_TOLERANCE_SECONDS = 300; // 5分钟时间容差

public function handle(array $payload, string $signature, string $timestamp) {
// 1. 验证时间戳有效性
if (abs(time() - (int)$timestamp) > self::WEBHOOK_TOLERANCE_SECONDS) {
throw new RuntimeException("Expired webhook");
}

// 2. 验证签名
$signingData = json_encode($payload)."|".$timestamp;
$expectedSig = hash_hmac('sha256', utf8_encode($signingData), utf8_encode(env('GCASH_SECRET')));

if (!hash_equals($expectedSig, $signature)) {
throw new RuntimeException("Invalid signature");
}

// 3. 处理业务逻辑(示例)
switch ($payload['event_type']) {
case 'payment.success':
return $this->handlePaymentSuccess(
$payload['data']['reference_id'],
floatval($payload['data']['amount'])
);

case 'payment.failed':
return $this->handlePaymentFailure(
json_decode($payload['data']['failure_details'], true)
);

default:
throw new RuntimeException("Unhandled event type");
}
}

private function handlePaymentSuccess(string refId float amount): void{
OrderService::markAsPaid(refId amount);
NotificationService::sendReceipt(refId);
}
}
?>

Python异步实现方案

from fastapi import APIRouter, Request, HTTPException  
import hmac

router = APIRouter()

@router.post("/webhooks/gcash")
async def gcash_webhook(request: Request):
payload = await request.json()
signature = request.headers.get("X-GCash-Signature")
timestamp = request.headers.get("X-GCash-Timestamp")

# Signature verification
message = f"{json.dumps(payload)}|{timestamp}".encode()

if not hmac.compare_digest(
hmac.new(config.GCASH_SECRET.encode(), message , "sha256").hexdigest(),
signature
): raise HTTPException(403 detail="Invalid signature")

# Process events asynchronously
match payload["event_type"]:
case "payment.success":
asyncio.create_task(process_success_payment(payload))
case _: logger.warning(f"Unhandled event:{event_type}")

return {"status": "ok"}

Maya支付状态查询与退款处理

PHP退款实现示例

<?php 

class MayaRefundService {

public function createRefund(string paymentId float amount string reason): array{
$endpoint="/payments/v1/payments/$paymentId/refunds";
$nonce=uniqid();

$body=[
"totalAmount"=>[
"value"=>number_format(amount2),
"currency"=>"PHP"
],
"reason"=>substr(reason0200)
];

$this->makeAuthenticatedRequest('POST' endpoint body);
}

private function makeAuthenticatedRequest(method path data){
/*生成Maya特有的认证头*/
authString=sprintf("%s:%s",API_KEY SECRET_KEY);

curl_setopt_array(ch [
CURLOPT_URL=>MAYA_API_BASE.path,
CURLOPT_USERPWD=>authString,
...
]);

return curl_exec(ch);
}
}
?>

Python订单状态查询示例

def get_maya_payment_status(payment_id: str)-> dict:
"""使用付款ID查询最终状态"""
try:
response=requests.get(
f"{base_url}/payments/{payment_id}",
auth=(api_key secret_key),
timeout=10)

response.raise_for_status()
status_map={
'PAYMENT_SUCCESS':'completed',
... #其他状态映射
}

return {'status': status_map[response.json()['state']] }

except requests.exceptions.RequestException as e:
logger.error(f"Maya API error:{str(e)}")
return {'error':'service_unavailable'}

PCI DSS合规要点(关键安全措施)

  1. 敏感数据处理

    #禁止日志记录完整卡号/PIN等数据  
    location ~* \.(php|py)$ {
    set_filtered_params on;
    log_filter "$arg_card_number [FILTERED]";
    log_filter "$arg_cvv [FILTERED]";
    }
  2. 加密存储要求

  • PHP建议使用defuse/php-encryption库:
    composer require defuse/php-encryption
  • Python推荐cryptography库:
    pip install cryptography

3.审计日志规范:应记录所有支付操作的关键字段(金额、结果代码)但需脱敏核心数据。

4.定期密钥轮换:建议通过自动化脚本每月更新API密钥:

bash脚本示例 #!/bin/bash rotate_gcash_keys(){ curl -XPATCH https://api.gcash.com/v1/auth/keys\?rotation=true \ -H "Authorization:Bearer $(vault read gcash/token)" }


需要我继续展开哪个具体方面的内容?例如:
1.GCash扫码支付的特定集成方式?
2.Maya分期付款功能的实现细节?
3.PHP/Python的PCI DSS合规工具链配置?

我将继续深入GCash和Maya支付集成的专业技术细节,分为以下几个关键方向:


一、GCash扫码支付深度集成(QR Code流程)

PHP动态生成收款码方案

class GcashQrService {
const QR_API = 'https://api.gcash.com/qrcode/v3/generate';

public function generateDynamicQr(
float $amount,
string $merchantTxId,
?string $description = null
): array {
$payload = [
'type' => 'DYNAMIC',
'amount' => round($amount, 2),
'referenceId' => substr(hash('sha256', uniqid().$merchantTxId), 0, 32),
'metadata' => [
'terminal_id' => env('GCASH_TERMINAL_ID'),
'description' => mb_substr($description ?? '', 0, 50)
]
];

// GCash要求特殊的JSON序列化方式(保留空数组)
$jsonPayload = json_encode($payload, JSON_PRESERVE_ZERO_FRACTION);

return Http::withHeaders([
'X-GCash-Timestamp' => time(),
// PHP的hash_hmac需要处理二进制密钥
'X-GCash-Signature' => hash_hmac('sha256',
utf8_encode($jsonPayload),
hex2bin(env('GCASH_SECRET_KEY'))
)
])
->post(self::QR_API, $payload)
->throw()
->json();
}
}

Python异步二维码状态轮询

import asyncio

class GcashQrMonitor:
def __init__(self):
self.callback_url = os.getenv('WEBHOOK_BASE') + "/gcash/qr-callback"

async def monitor_qr_status(self, qr_id: str, timeout=300):
"""轮询二维码状态直到超时或完成"""
start_time = time.time()
while (time.time() - start_time) < timeout:
status_resp = await self._get_qr_status(qr_id)
if status_resp['status'] in ['PAID','EXPIRED']:
return status_resp

await asyncio.sleep(5) # GCash建议5秒间隔

raise TimeoutError("QR payment monitoring timeout")

async def _get_qr_status(self qrid):
async with aiohttp.ClientSession() as session:
resp=await session.get(
f"https://api.gcash.com/qrcode/v1/transactions/{qrid}",
headers={'Authorization': f"Bearer {self.api_key}"})
return await resp.json()

二、Maya分期付款实现方案

PHP信用卡分期处理(需PCI SAQ D认证)

// Maya分期特有参数构建示例
$installmentOptions = [];

foreach ([3,6]12] as months){
$options[]=[
'tenure'=>months,
// Maya要求精确计算每期金额(含手续费)
'monthlyAmount'=>round(total*(1+INSTALLMENT_RATE[months])/months2),
];
}

$paymentData=[
'source'=>[
// token必须通过MayaJS在前端加密获得
'token'=>$cardToken],
...
];

// Maya对分期的特殊验证流程
if(count(options)>0){
$this->validateMerchantTier(); //检查商户等级是否允许分期

/*强制显示分期选项*/
response=$mayaClient->post('/checkout/v1/installments'
['transactionReference'=>$txRef]);
}

Python处理回调中的3DS验证:

def handle_3ds_callback(request_data):
"""处理Maya的3D Secure重定向回调"""
threeds_session=request_data['threeDSSessionData']
try:
# Maya要求同步校验CAVV值
verify_cavv(threeds_session['cavv'])

#更新原交易记录为已认证状态
Payment.objects.filter(
session_id=threeds_session['parentSession']
).update(
authentication_status='Y',
eci=threeds_session['eci'],
updated_at=timezone.now()
)

except MayalnvalidCavvError:
log_security_event(f"3DS欺诈尝试:{request.META.REMOTE_ADDR}")
raise PermissionDenied("Authentication failed")

三、生产环境关键安全配置清单

项目 PHP解决方案 Python解决方案
API密钥存储 Laravel Vault或AWS Secrets Manager AWS Parameter Store + boto3缓存
HTTP传输加密 CURLOPT_SSL_VERIFYPEER=true强制启用 requests.Session(mount=’https://…’)
SQL注入防护 PDO预处理语句+Eloquent ORM SQLAlchemy Core + psycopg2参数化查询
Webhook IP白名单 $_SERVER[‘REMOTE_ADDR’]过滤 Django ALLOWED_HOSTS动态验证

四、调试与故障排查技巧

  1. 常见错误代码处理

    • GCash 400113:通常表示签名算法错误 → PHP签名生成工具
    • Maya MPG-012:金额格式问题 → number_format(amount ,2,'.',",")
  2. 日志记录规范示例

# logging.conf分段配置示例  
[handler_gcashHandler]
class=handlers.TimedRotatingFileHandler
level=DEBUG
formatter=gPayFormat

[formatter_gPayFormat]
format={"timestamp":"%(asctime)s","level":"%(levelname)s","event":"%(message)s"} # JSON结构化日志 ```

---

如果需要更深入的特定场景实现方案,例如:
- 🇵🇭菲律宾本地化税务计算集成(VAT/Percentage Tax)
- 🛡️硬件安全模块(HSM)集成指南
- 📱React Native混合开发桥接方案