将第三方支付网关有效地集成到 WordPress 插件中以销售数字产品至关重要。本指南演示了所有重要程序,从网关选择开始,到复杂的安全协议和合规标准结束。您开发支付插件的知识将帮助您了解如何构建可扩展并提供用户友好功能的安全系统。
1. 选择合适的支付网关
需要考虑的关键因素
- 支持的功能:确保网关支持数字产品、订阅和退款。
- 全球覆盖:它是否支持多种货币和地区(例如,Stripe 与 PayPal)?
- API 文档:查找包含代码示例的清晰、维护良好的文档。
- 费用:比较交易费用(例如,Stripe 收取每笔交易 2.9% + 0.30 美元)。
- PCI 合规性:选择可最大限度地减少 PCI-DSS 范围的网关(例如,Stripe.js用于令牌化)。
流行的支付网关
- Stripe:开发人员友好,具有强大的 API,非常适合订阅和全球支付。
- PayPal:支持一次性付款和定期付款,但某些流程需要 PayPal 账户。
- Square:为小型企业提供简单的定价和简单的设置。
- Authorize.Net:具有高级欺诈检测功能的企业级解决方案。
2. 设置安全环境
第 1 步:强制执行 HTTPS
所有与支付相关的流量都必须使用 HTTPS。使用 Really Simple SSL 将 HTTP 重定向到 HTTPS:
// In wp-config.php
define('FORCE_SSL_ADMIN', true);
第 2 步:安全地存储 API 密钥
切勿对 API 密钥进行硬编码。使用环境变量或加密的数据库存储。
示例:加密 Stripe 密钥
// In wp-config.php
define('STRIPE_SECRET_KEY', 'sk_test_...');
define('STRIPE_WEBHOOK_SECRET', 'whsec_...');
// Encrypt keys before saving to the database
$encrypted_key = openssl_encrypt(STRIPE_SECRET_KEY, 'AES-256-CBC', SECURE_AUTH_KEY);
update_option('stripe_encrypted_secret', $encrypted_key);
第 3 步:令牌化
使用客户端令牌化以避免处理原始信用卡数据。对于 Stripe:
// Frontend: Create a Stripe Elements form
const stripe = Stripe('pk_test_...');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
// On form submission
stripe.createToken(cardElement).then(function(result) {
if (result.error) {
alert(result.error.message);
} else {
// Send token to server
jQuery.post('/wp-admin/admin-ajax.php', {
action: 'process_payment',
stripe_token: result.token.id
});
}
});
3. API 通信和服务器端处理
第 1 步:服务器端付款处理
==使用 wp_remote_post()== 与支付网关的 API 进行交互。
示例:Stripe 收款请求
function process_payment() {
$stripe_secret = defined('STRIPE_SECRET_KEY') ? STRIPE_SECRET_KEY : get_option('stripe_secret_key');
$token = sanitize_text_field($_POST['stripe_token']);
$amount = absint($_POST['amount']); // In cents
$response = wp_remote_post('https://api.stripe.com/v1/charges', [
'headers' => [
'Authorization' => 'Bearer ' . $stripe_secret,
'Content-Type' => 'application/x-www-form-urlencoded',
],
'body' => [
'amount' => $amount,
'currency' => 'usd',
'source' => $token,
'description' => sanitize_text_field($_POST['product_name']),
],
]);
// Handle response (covered in Section 4)
}
add_action('wp_ajax_process_payment', 'process_payment');
add_action('wp_ajax_nopriv_process_payment', 'process_payment');
第 2 步:输入验证
清理并验证所有用户输入:
$email = sanitize_email($_POST['email']);
$product_id = absint($_POST['product_id']);
$currency = sanitize_text_field($_POST['currency']);
4. 高级错误处理和日志记录
第 1 步:正常错误响应
处理 API 错误、超时和无效响应:
if (is_wp_error($response)) {
error_log('Payment API error: ' . $response->get_error_message());
wp_send_json_error([
'message' => 'Payment gateway unreachable. Please try again.'
]);
} else {
$body = json_decode(wp_remote_retrieve_body($response), true);
if (isset($body['error'])) {
error_log('Stripe error: ' . $body['error']['message']);
wp_send_json_error(['message' => $body['error']['message']]);
} else {
// Save transaction ID to database
global $wpdb;
$wpdb->insert('wp_transactions', [
'transaction_id' => sanitize_text_field($body['id']),
'amount' => $body['amount'] / 100,
'status' => 'completed'
]);
wp_send_json_success(['receipt_url' => $body['receipt_url']]);
}
}
第 2 步:日志记录和监控
使用 Query Monitor 或自定义日志记录来跟踪错误:
function log_payment_error($error, $context = []) {
if (WP_DEBUG_LOG) {
error_log('[Payment Error] ' . $error . ' | Context: ' . print_r($context, true));
}
}
// Example usage
log_payment_error('Invalid currency', ['currency' => $_POST['currency']]);
第 3 步:回退机制
如果主网关失败,请提供替代支付方式:
if ($gateway_unreachable) {
wp_send_json_error([
'message' => 'Stripe is unavailable. Please try PayPal.',
'fallback' => [
'url' => 'https://paypal.com/checkout',
'method' => 'paypal'
]
]);
}
5. 安全最佳实践
实践 1:限速
通过限制付款尝试来防止暴力攻击:
$user_ip = $_SERVER['REMOTE_ADDR'];
$transient_key = 'payment_attempts_' . $user_ip;
$attempts = get_transient($transient_key) ?: 0;
if ($attempts >= 5) {
wp_send_json_error(['message' => 'Too many attempts. Try again in 1 hour.']);
} else {
set_transient($transient_key, $attempts + 1, HOUR_IN_SECONDS);
}
实践 2:CSRF 保护的 Nonces
将 nonce 添加到付款表单中:
// Frontend
wp_nonce_field('process_payment_nonce', 'payment_nonce');
// Backend
if (!wp_verify_nonce($_POST['payment_nonce'], 'process_payment_nonce')) {
wp_send_json_error(['message' => 'Invalid request.']);
}
实践 3:定期安全审计
使用 WPScan 等工具检查漏洞并更新依赖项。
6. PCI-DSS 合规性和欺诈预防
缩小 PCI 范围
- 标记化:使用 Stripe.js 或 PayPal Smart Button 来避免处理原始卡数据。
- Hosted Payment Pages:将用户重定向到网关页面(例如 PayPal)。
欺诈检测工具
- Stripe Radar:基于机器学习的欺诈检测。
- 筛选:实时风险评分。
示例:启用 Stripe Radar
$response = wp_remote_post('https://api.stripe.com/v1/charges', [
'headers' => ['Authorization' => 'Bearer ' . STRIPE_SECRET_KEY],
'body' => [
'amount' => 1000,
'currency' => 'usd',
'source' => $token,
'radar_options' => ['enable_risk_actions' => 'true']
]
]);
7. 用于异步处理的 Webhook
第 1 步:设置 Webhook
为 Webhook 创建自定义 REST API 端点:
add_action('rest_api_init', function() {
register_rest_route('payment/v1', '/stripe-webhook', [
'methods' => 'POST',
'callback' => 'handle_stripe_webhook',
'permission_callback' => '__return_true'
]);
});
function handle_stripe_webhook(WP_REST_Request $request) {
$payload = $request->get_body();
$sig_header = $request->get_header('stripe-signature');
try {
$event = \Stripe\Webhook::constructEvent(
$payload,
$sig_header,
STRIPE_WEBHOOK_SECRET
);
switch ($event->type) {
case 'payment_intent.succeeded':
// Update order status
break;
case 'charge.refunded':
// Process refund
break;
}
return new WP_REST_Response('Webhook processed', 200);
} catch (Exception $e) {
error_log('Webhook error: ' . $e->getMessage());
return new WP_Error('invalid_signature', 'Invalid signature', ['status' => 403]);
}
}
8. 本地化和多币种支持
第 1 步:货币格式
使用 number_format_i18n() 根据用户的区域设置设置价格格式:
$price = 1000; // In cents
$formatted_price = number_format_i18n($price / 100, 2);
echo get_woocommerce_currency_symbol() . $formatted_price;
第 2 步:地理定位
检测用户国家/地区并动态设置货币:
$geo = new WC_Geolocation();
$country = $geo->geolocate_ip($_SERVER['REMOTE_ADDR'])['country'];
$currency = ($country === 'GB') ? 'GBP' : 'USD';
9. 订阅管理
第 1 步:使用 Stripe 进行定期付款
使用 Stripe API 创建订阅:
$response = wp_remote_post('https://api.stripe.com/v1/subscriptions', [
'headers' => ['Authorization' => 'Bearer ' . STRIPE_SECRET_KEY],
'body' => [
'customer' => $customer_id,
'items' => [['price' => 'price_12345']]
]
]);
第 2 步:处理取消
使用 Webhook 检测订阅取消并更新您的数据库:
case 'customer.subscription.deleted':
$subscription_id = $event->data->object->id;
$wpdb->update('wp_subscriptions', ['status' => 'canceled'], ['stripe_id' => $subscription_id]);
break;
10. 测试和调试
第 1 步:模拟边缘情况
- 付款失败:使用 4000000000000002 等测试卡(Stripe 的“付款失败”卡)。
- 网络错误:暂时禁用 Internet 以测试超时。
第 2 步:自动化测试
为关键流编写 PHPUnit 测试:
public function test_payment_success() {
$_POST['stripe_token'] = 'tok_visa';
$response = $this->process_payment();
$this->assertTrue($response['success']);
}
F经常提出的问题
1. 我该如何处理退款?
使用网关退款 API:
wp_remote_post('https://api.stripe.com/v1/refunds', [ 'headers' => ['Authorization' => 'Bearer ' . STRIPE_SECRET_KEY], 'body' => ['charge' => $charge_id] ]);
2. 我可以支持多个网关吗?
是的! 根据用户的选择,使用工厂模式在 Stripe、PayPal 等之间切换。
3. 如何保护用户数据?
- 加密敏感数据。
- 通过提供数据导出/删除选项来遵守 GDPR。
4. 如果 API 发生变化怎么办?
订阅网关的 API 更改日志并在暂存环境中测试更新。
5. 我如何处理货币兑换?
让网关处理转换或使用 Open Exchange Rates 等服务。
结论
将第三方支付网关集成到 WordPress 插件中需要密切关注安全性、错误处理和用户体验。通过利用令牌化、webhook 和欺诈检测等工具,您可以构建一个既安全又可扩展的系统。始终优先考虑遵守 PCI-DSS 和 GDPR,并在实际条件下严格测试您的集成。如需进一步学习,请浏览 Stripe API 文档和 WordPress REST API 手册。