本文目录导读:

- 核心概念区分
- 数据库设计(MySQL/PostgreSQL)
- PHP 格式化函数
- 电子奈拉(eNGN)特殊处理
- 核心逻辑:NGN与eNGN的兑换(Conversion)
- API 注意事项(与银行或CBN集成)
- 常见陷阱总结
- 推荐的库(用于更严谨的货币处理)
这是一个关于PHP项目中处理尼日利亚奈拉(NGN) 与电子奈拉(eNGN) 的技术指南。
核心概念区分
- NGN(Physical Naira):传统法定货币奈拉,通常以₦符号表示,小数点后保留2位(即Kobo,1 NGN = 100 Kobo)。
- eNGN(e-Naira / Digital Naira):尼日利亚中央银行(CBN)发行的中央银行数字货币(CBDC)。从技术角度看,eNGN与NGN的数值是1:1锚定的,即1 eNGN = 1 NGN,它并非一种新的加密资产(如USDT),而是一种数字版本的奈拉。
关键差异(对开发者而言):
- 存储与分类:通常需要在数据库中区分是“普通货币”(NGN)还是“数字货币”(eNGN)。
- 合规性:eNGN的交易可能受CBN特定的API或钱包规则约束(例如KYC要求、钱包限额)。
- 转化:用户需要拥有一个eNaira Speed Wallet或通过银行API进行从NGN到eNGN(存入)以及从eNGN到NGN(提现)的操作。
数据库设计(MySQL/PostgreSQL)
建议在 transactions 和 wallets 表中增加 currency_type 字段。
CREATE TABLE wallets (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
-- 主要存储奈拉钱包(普通资金)
ngn_balance DECIMAL(18, 2) DEFAULT 0.00,
-- 电子奈拉钱包余额
enaira_balance DECIMAL(18, 2) DEFAULT 0.00,
-- 或者统一存储为单个字段,但用type区分
-- balance DECIMAL(18,2),
-- currency_type ENUM('NGN', 'eNGN')
);
CREATE TABLE transactions (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
type ENUM('DEPOSIT', 'WITHDRAW', 'TRANSFER', 'CONVERSION','PURCHASE'),
currency_type ENUM('NGN', 'eNGN'),
amount DECIMAL(18, 2) NOT NULL,
fee DECIMAL(18, 2) DEFAULT 0.00,
reference VARCHAR(100) UNIQUE,
status ENUM('PENDING', 'SUCCESS', 'FAILED') DEFAULT 'PENDING',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
提示:由于NGN与eNGN价值相同,可以共用货币格式化函数,但必须通过 currency_type 控制业务流程。
PHP 格式化函数
NGN的格式化通常涉及:
- 使用
number_format - 添加奈拉符号
- 某些场景下需要处理Kobo(分)
<?php
/**
* 格式化尼日利亚奈拉金额
*
* @param float|string $amount
* @param bool $showSymbol 是否显示₦符号
* @param bool $includeKobo 是否包含小数(Kobo)
* @return string
*/
function formatNaira($amount, bool $showSymbol = true, bool $includeKobo = true): string
{
// 强制转换为float
$amountFloat = floatval($amount);
if ($includeKobo) {
// 标准格式:₦1,234.56
$formatted = number_format($amountFloat, 2, '.', ',');
} else {
// 整数格式:₦1,234(如显示商品价格时)
$formatted = number_format($amountFloat, 0, '.', ',');
}
if ($showSymbol) {
// Unicode 奈拉符号 ₦ (U+20A6)
return '₦' . $formatted;
}
return $formatted;
}
/**
* 将金额转换为Kobo(分)
* 1 NGN = 100 Kobo
*
* @param float $amount
* @return int
*/
function nairaToKobo(float $amount): int
{
return intval(round($amount * 100));
}
/**
* 从Kobo转换为奈拉
*
* @param int $kobo
* @return float
*/
function koboToNaira(int $kobo): float
{
return $kobo / 100;
}
// 使用示例
echo formatNaira(2500.50); // 输出:₦2,500.50
echo formatNaira(0.75, true, true); // 输出:₦0.75
电子奈拉(eNGN)特殊处理
eNGN的数值显示与NGN完全一致,但通常需要明确标注“e-Naira”或“Digital Naira”来区分账本。
<?php
/**
* 格式化电子奈拉金额
* 电子奈拉目前与奈拉等值,但通常建议保留2位小数
*
* @param float $amount
* @param bool $showType 是否显示类型标签
* @return string
*/
function formatENaira($amount, bool $showType = true): string
{
$formatted = '₦' . number_format(floatval($amount), 2, '.', ',');
if ($showType) {
return $formatted . ' eNGN';
}
return $formatted;
}
// 示例
echo formatENaira(1500.00); // 输出:₦1,500.00 eNGN
核心逻辑:NGN与eNGN的兑换(Conversion)
用户可以在两者之间转换,但需要注意:
- CBN规则:目前转换通常需要通过银行或NIBSS API完成,系统中应记录内部转换并生成唯一参考号。
- 速率:始终为1:1,没有汇率差,但可能会有固定手续费(如₦10)。
<?php
/**
* 模拟将NGN转换为eNGN
*
* @param int $userId
* @param float $amount (单位:奈拉)
* @return array ['success' => bool, 'message' => string, 'reference' => string|null]
*/
function convertNgnToEnaira(int $userId, float $amount, PDO $pdo): array
{
// 1. 验证金额
if ($amount <= 0) {
return ['success' => false, 'message' => '无效金额'];
}
// 2. 检查用户NGN余额(示例:从数据库查询)
$balance = getUserBalance($userId, 'NGN'); // 假设该函数返回用户NGN余额
if ($balance < $amount) {
return ['success' => false, 'message' => '奈拉余额不足'];
}
// 3. 开始数据库事务
try {
$pdo->beginTransaction();
// 生成唯一参考号
$reference = 'CONV_NGN_ENGN_' . uniqid() . '_' . time();
// 4. 扣除NGN余额
$stmt1 = $pdo->prepare("UPDATE wallets SET ngn_balance = ngn_balance - :amount WHERE user_id = :user_id");
$stmt1->execute([':amount' => $amount, ':user_id' => $userId]);
// 5. 增加eNGN余额
$stmt2 = $pdo->prepare("UPDATE wallets SET enaira_balance = enaira_balance + :amount WHERE user_id = :user_id");
$stmt2->execute([':amount' => $amount, ':user_id' => $userId]);
// 6. 记录交易日志
$stmt3 = $pdo->prepare("INSERT INTO transactions (user_id, type, currency_type, amount, reference, status)
VALUES (:user_id, 'CONVERSION', 'NGN', :amount_ngn, :ref1, 'SUCCESS')");
$stmt3->execute([
':user_id' => $userId,
':amount_ngn' => $amount * -1, // 负数表示扣减
':ref1' => $reference . '_NGN_OUT'
]);
$stmt4 = $pdo->prepare("INSERT INTO transactions (user_id, type, currency_type, amount, reference, status)
VALUES (:user_id, 'CONVERSION', 'eNGN', :amount_engn, :ref2, 'SUCCESS')");
$stmt4->execute([
':user_id' => $userId,
':amount_engn' => $amount,
':ref2' => $reference . '_ENGN_IN'
]);
$pdo->commit();
return ['success' => true, 'message' => '转换成功', 'reference' => $reference];
} catch (Exception $e) {
$pdo->rollBack();
return ['success' => false, 'message' => '数据库错误:' . $e->getMessage()];
}
}
API 注意事项(与银行或CBN集成)
当你的PHP项目需要与尼日利亚银行系统或eNaira Speed Wallet API交互时,需注意:
| 参数 | 说明 |
|---|---|
| 金额格式 | 很多银行API要求金额为 Kobo(整数,如 ₦2500 应发送 250000)。 |
| 参考号 | 必须是唯一的字符串,建议使用 YmdHis + 随机数 + 用户ID。 |
| NIBSS | 如果涉及跨银行直接转账(NIP),需要遵循NIBSS协议,PHP端通常通过HTTP/SOAP发送XML。 |
| eNaira API | 官方API可能需要特定的加密(如3DES、RSA签名),或使用OAUTH2令牌。 |
示例:发送金额前转换为Kobo
<?php
/**
* 准备发送给银行API的金额(NGN转Kobo)
*/
$ngnAmount = 2500.00;
$koboAmount = nairaToKobo($ngnAmount); // 250000
$apiPayload = [
'amount' => $koboAmount,
'currency' => 'NGN', // 或 'eNGN' 取决于接口
'narration' => 'Payment for services',
'reference' => 'TXN_' . time() . '_' . rand(100,999)
];
// 发送给银行API
// $response = httpPost($apiEndpoint, $apiPayload);
常见陷阱总结
- 浮点数精度:PHP的
float在大量计算时可能不精确。建议:所有货币金额在数据库中存储为DECIMAL(18,2),在PHP中计算时使用int(以Kobo为单位),最后再格式化显示。 - 不要混淆符号:虽然eNGN也是以 表示,但在UI中最好加上“e-Naira”或“Digital”前缀,避免用户误解为普通余额。
- 合规性标记:所有涉及eNGN的交易记录必须保存更多数据(如用户钱包ID、KYC等级、交易类型coded),以便CBN审计。
推荐的库(用于更严谨的货币处理)
- moneyphp/money:支持NGN货币代码,可处理小数和格式化。
- brick/money:不可变的货币对象库,适合复杂金融计算。
如果你需要针对特定场景(例如Paystack、Flutterwave集成eNaira,或离线钱包生成)的代码,请补充更多细节。