本文目录导读:

我来为您详细解释PHP项目中处理数字印尼盾(IDR)和eIDR(电子印尼盾/数字货币印尼盾)的相关技术实现。
基础概念
数字印尼盾 vs eIDR
| 类型 | 描述 | 特点 |
|---|---|---|
| IDR | 传统印尼盾 | 法定货币,面额大,需处理大数字 |
| eIDR | 电子印尼盾(数字货币) | 通常以更小单位存储,需处理精度 |
PHP 数字处理方案
金额存储与格式化
<?php
class IDRHandler {
// 印尼盾格式化(带千分位)
public static function formatIDR($amount, $decimal = 0) {
return 'Rp ' . number_format($amount, $decimal, ',', '.');
}
// eIDR格式化(通常有小数位)
public static function formatEIDR($amount, $decimal = 2) {
return number_format($amount, $decimal, '.', ',');
}
// 转换eIDR到IDR(假设1 eIDR = 1 IDR)
public static function eIDRToIDR($eidrAmount) {
return (int) round($eidrAmount);
}
// IDR转eIDR
public static function IDRToEIDR($idrAmount) {
return (float) $idrAmount;
}
}
echo IDRHandler::formatIDR(1500000); // Rp 1.500.000
echo IDRHandler::formatEIDR(1500000.50); // 1,500,000.50
?>
大数字处理(防止溢出)
印尼盾面额大,需使用高精度处理:
<?php
use Brick\Math\BigDecimal;
use Brick\Math\RoundingMode;
class IDRBigMath {
// 使用BCMath或BigDecimal处理大数字
public static function add($amount1, $amount2) {
return bcadd($amount1, $amount2, 2);
}
public static function multiply($amount, $rate) {
return bcmul($amount, $rate, 2);
}
public static function format($amount, $currency = 'IDR') {
if ($currency === 'IDR') {
return 'Rp ' . number_format((int)$amount, 0, ',', '.');
}
return number_format((float)$amount, 2, '.', ',');
}
}
// 处理大额交易
$purchase = '1000000000000'; // 1万亿
$tax = bcmul($purchase, '0.11', 2); // 11%税
echo IDRBigMath::format($tax); // Rp 110.000.000.000
?>
数据库设计
MySQL 表结构
-- 账户表
CREATE TABLE accounts (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT,
balance_idr DECIMAL(20,2) DEFAULT 0.00, -- IDR余额
balance_eidr DECIMAL(20,8) DEFAULT 0.00000000, -- eIDR余额(更高精度)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 交易记录表
CREATE TABLE transactions (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
transaction_id VARCHAR(36) UNIQUE,
from_account BIGINT,
to_account BIGINT,
amount DECIMAL(20,2), -- IDR金额
amount_eidr DECIMAL(20,8), -- eIDR金额(如果需要)
currency ENUM('IDR', 'eIDR') NOT NULL,
status ENUM('pending', 'completed', 'failed') DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 汇率表(如果eIDR与IDR不同)
CREATE TABLE exchange_rates (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
from_currency VARCHAR(10),
to_currency VARCHAR(10),
rate DECIMAL(20,8),
effective_date DATE
);
交易处理类
<?php
class EIDRTransaction {
private $db;
private $precision = 8; // eIDR精度
public function __construct($dbConnection) {
$this->db = $dbConnection;
}
// IDR转账
public function transferIDR($fromUserId, $toUserId, $amount) {
try {
$this->db->beginTransaction();
// 检查余额
$fromBalance = $this->getBalanceIDR($fromUserId);
if ($fromBalance < $amount) {
throw new Exception("IDR余额不足");
}
// 扣款
$this->updateBalanceIDR($fromUserId, -$amount);
// 加款
$this->updateBalanceIDR($toUserId, $amount);
// 记录交易
$this->recordTransaction([
'from' => $fromUserId,
'to' => $toUserId,
'amount' => $amount,
'currency' => 'IDR'
]);
$this->db->commit();
return true;
} catch (Exception $e) {
$this->db->rollback();
throw $e;
}
}
// eIDR转账(带精度处理)
public function transferEIDR($fromUserId, $toUserId, $eidrAmount) {
$eidrAmount = number_format((float)$eidrAmount, $this->precision, '.', '');
try {
$this->db->beginTransaction();
$fromBalance = $this->getBalanceEIDR($fromUserId);
if (bccomp($fromBalance, $eidrAmount, $this->precision) < 0) {
throw new Exception("eIDR余额不足");
}
$this->updateBalanceEIDR($fromUserId, '-' . $eidrAmount);
$this->updateBalanceEIDR($toUserId, $eidrAmount);
$this->recordTransaction([
'from' => $fromUserId,
'to' => $toUserId,
'amount_eidr' => $eidrAmount,
'currency' => 'eIDR'
]);
$this->db->commit();
return true;
} catch (Exception $e) {
$this->db->rollback();
throw $e;
}
}
// 获取IDR余额
private function getBalanceIDR($userId) {
$stmt = $this->db->prepare("SELECT balance_idr FROM accounts WHERE user_id = ?");
$stmt->execute([$userId]);
return $stmt->fetchColumn();
}
// 获取eIDR余额
private function getBalanceEIDR($userId) {
$stmt = $this->db->prepare("SELECT balance_eidr FROM accounts WHERE user_id = ?");
$stmt->execute([$userId]);
return $stmt->fetchColumn();
}
// 更新IDR余额
private function updateBalanceIDR($userId, $amount) {
$stmt = $this->db->prepare(
"UPDATE accounts SET balance_idr = balance_idr + ? WHERE user_id = ?"
);
$stmt->execute([$amount, $userId]);
}
// 更新eIDR余额(使用字符串避免精度问题)
private function updateBalanceEIDR($userId, $amount) {
$stmt = $this->db->prepare(
"UPDATE accounts SET balance_eidr = balance_eidr + CAST(? AS DECIMAL(20,8)) WHERE user_id = ?"
);
$stmt->execute([$amount, $userId]);
}
private function recordTransaction($tx) {
$stmt = $this->db->prepare(
"INSERT INTO transactions (transaction_id, from_account, to_account, amount, amount_eidr, currency)
VALUES (UUID(), ?, ?, ?, ?, ?)"
);
$stmt->execute([
$tx['from'],
$tx['to'],
$tx['amount'] ?? 0,
$tx['amount_eidr'] ?? 0,
$tx['currency']
]);
}
}
?>
前端展示与交互
<?php
// 在视图中使用
$idrAmount = 1500000;
$eidrAmount = 1.50000000;
echo "传统显示: " . number_format($idrAmount, 0, ',', '.') . " IDR\n";
echo "科学显示: " . number_format($eidrAmount, 2, ',', '.') . " eIDR\n";
echo "智能显示: " . ((int)$idrAmount >= 1000) ?
number_format($idrAmount/1000000, 1) . " Juta IDR" :
number_format($idrAmount, 0, ',', '.') . " IDR";
?>
安全注意事项
- 浮点运算问题:始终使用
BCMath或Decimal类 - 输入验证:严格验证数字格式,防止注入
- 事务管理:所有金额操作使用数据库事务
- 日志记录:记录所有金额变更操作
推荐使用的库
# 安装高精度数学库 composer require brick/math composer require moneyphp/money
关键要点:
- 大金额用
DECIMAL类型存储 - 使用
bcmath扩展进行运算 - eIDR 可能需要更高精度(8-10位小数)
- 始终使用事务保证数据一致性