PHP项目数字尼日利亚奈拉与eNGN

wen PHP项目 1

本文目录导读:

PHP项目数字尼日利亚奈拉与eNGN

  1. 核心概念区分
  2. 数据库设计(MySQL/PostgreSQL)
  3. PHP 格式化函数
  4. 电子奈拉(eNGN)特殊处理
  5. 核心逻辑:NGN与eNGN的兑换(Conversion)
  6. API 注意事项(与银行或CBN集成)
  7. 常见陷阱总结
  8. 推荐的库(用于更严谨的货币处理)

这是一个关于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)

建议在 transactionswallets 表中增加 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);

常见陷阱总结

  1. 浮点数精度:PHP的 float 在大量计算时可能不精确。建议:所有货币金额在数据库中存储为 DECIMAL(18,2) ,在PHP中计算时使用 int(以Kobo为单位),最后再格式化显示。
  2. 不要混淆符号:虽然eNGN也是以 表示,但在UI中最好加上“e-Naira”或“Digital”前缀,避免用户误解为普通余额。
  3. 合规性标记:所有涉及eNGN的交易记录必须保存更多数据(如用户钱包ID、KYC等级、交易类型coded),以便CBN审计。

推荐的库(用于更严谨的货币处理)

  • moneyphp/money:支持NGN货币代码,可处理小数和格式化。
  • brick/money:不可变的货币对象库,适合复杂金融计算。

如果你需要针对特定场景(例如Paystack、Flutterwave集成eNaira,或离线钱包生成)的代码,请补充更多细节。

抱歉,评论功能暂时关闭!