本文目录导读:

我来详细介绍如何用PHP实现一个完整的提现系统,包括核心功能和安全措施。
数据库设计
提现申请表
CREATE TABLE `withdrawals` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`amount` decimal(10,2) NOT NULL,
`fee` decimal(10,2) DEFAULT '0.00',
`actual_amount` decimal(10,2) NOT NULL,
`payment_method` varchar(50) NOT NULL,
`account_info` text NOT NULL,
`status` enum('pending','processing','success','failed','cancelled') DEFAULT 'pending',
`created_at` datetime NOT NULL,
`processed_at` datetime DEFAULT NULL,
`admin_note` text,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `status` (`status`)
);
-- 用户余额表
CREATE TABLE `user_balances` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`balance` decimal(10,2) DEFAULT '0.00',
`frozen_amount` decimal(10,2) DEFAULT '0.00',
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_id` (`user_id`)
);
提现配置文件
// config/withdrawal.php
return [
'min_amount' => 10.00,
'max_amount' => 10000.00,
'daily_limit' => 3,
'daily_amount_limit' => 50000.00,
'fee_rate' => 0.01, // 1%手续费
'payment_methods' => [
'alipay' => '支付宝',
'wechat' => '微信',
'bank_card' => '银行卡'
],
'audit_required' => true, // 是否需要审核
'auto_process' => false, // 是否自动处理
'supported_currencies' => ['CNY']
];
核心提现类
<?php
// classes/WithdrawalSystem.php
class WithdrawalSystem {
private $db;
private $config;
public function __construct($db) {
$this->db = $db;
$this->config = require 'config/withdrawal.php';
}
/**
* 创建提现申请
*/
public function createWithdrawal($userId, $amount, $paymentMethod, $accountInfo) {
// 1. 验证用户身份
if (!$this->verifyUser($userId)) {
throw new Exception("用户验证失败");
}
// 2. 检查提现限制
$this->validateWithdrawal($userId, $amount);
// 3. 计算手续费
$fee = $this->calculateFee($amount);
$actualAmount = $amount - $fee;
// 4. 开启事务
$this->db->beginTransaction();
try {
// 5. 冻结余额
$this->freezeBalance($userId, $amount);
// 6. 创建提现记录
$stmt = $this->db->prepare(
"INSERT INTO withdrawals
(user_id, amount, fee, actual_amount, payment_method, account_info, created_at)
VALUES (?, ?, ?, ?, ?, ?, NOW())"
);
$stmt->execute([
$userId, $amount, $fee, $actualAmount,
json_encode($paymentMethod), json_encode($accountInfo)
]);
$withdrawalId = $this->db->lastInsertId();
// 7. 记录日志
$this->logWithdrawal($userId, $withdrawalId, 'create');
$this->db->commit();
return $withdrawalId;
} catch (Exception $e) {
$this->db->rollBack();
throw $e;
}
}
/**
* 验证提现申请
*/
private function validateWithdrawal($userId, $amount) {
// 检查最低提现金额
if ($amount < $this->config['min_amount']) {
throw new Exception("提现金额不能低于 {$this->config['min_amount']} 元");
}
// 检查最高提现金额
if ($amount > $this->config['max_amount']) {
throw new Exception("单次提现金额不能超过 {$this->config['max_amount']} 元");
}
// 检查用户余额
$balance = $this->getUserBalance($userId);
if ($balance < $amount) {
throw new Exception("余额不足,当前余额:{$balance} 元");
}
// 检查每日提现次数
$todayCount = $this->getTodayWithdrawalCount($userId);
if ($todayCount >= $this->config['daily_limit']) {
throw new Exception("每日提现次数已达上限");
}
// 检查每日提现金额限制
$todayAmount = $this->getTodayWithdrawalAmount($userId);
if ($todayAmount + $amount > $this->config['daily_amount_limit']) {
throw new Exception("每日提现金额已达上限");
}
}
/**
* 处理提现(管理员操作)
*/
public function processWithdrawal($withdrawalId, $action, $adminId, $note = '') {
$withdrawal = $this->getWithdrawalById($withdrawalId);
if (!$withdrawal) {
throw new Exception("提现记录不存在");
}
if ($withdrawal['status'] != 'pending') {
throw new Exception("只能处理待审核的提现");
}
$this->db->beginTransaction();
try {
switch ($action) {
case 'approve':
$this->approveWithdrawal($withdrawal, $adminId);
break;
case 'reject':
$this->rejectWithdrawal($withdrawal, $adminId, $note);
break;
case 'complete':
$this->completeWithdrawal($withdrawal, $adminId);
break;
default:
throw new Exception("无效操作");
}
$this->db->commit();
return true;
} catch (Exception $e) {
$this->db->rollBack();
throw $e;
}
}
/**
* 批准提现
*/
private function approveWithdrawal($withdrawal, $adminId) {
// 更新状态为处理中
$stmt = $this->db->prepare(
"UPDATE withdrawals SET status='processing', processed_at=NOW()
WHERE id=?"
);
$stmt->execute([$withdrawal['id']]);
// 记录操作日志
$this->logWithdrawalAdmin($withdrawal['user_id'], $withdrawal['id'], 'approve', $adminId);
}
/**
* 拒绝提现
*/
private function rejectWithdrawal($withdrawal, $adminId, $note) {
// 解冻余额
$this->unfreezeBalance($withdrawal['user_id'], $withdrawal['amount']);
// 更新状态
$stmt = $this->db->prepare(
"UPDATE withdrawals SET status='failed', admin_note=?, processed_at=NOW()
WHERE id=?"
);
$stmt->execute([$note, $withdrawal['id']]);
// 记录操作日志
$this->logWithdrawalAdmin($withdrawal['user_id'], $withdrawal['id'], 'reject', $adminId);
}
/**
* 完成提现(打款成功)
*/
private function completeWithdrawal($withdrawal, $adminId) {
// 扣除冻结余额
$this->deductFrozenBalance($withdrawal['user_id'], $withdrawal['amount']);
// 更新状态
$stmt = $this->db->prepare(
"UPDATE withdrawals SET status='success', processed_at=NOW()
WHERE id=?"
);
$stmt->execute([$withdrawal['id']]);
// 记录操作日志
$this->logWithdrawalAdmin($withdrawal['user_id'], $withdrawal['id'], 'complete', $adminId);
// 发送通知
$this->sendWithdrawalNotification($withdrawal['user_id'], $withdrawal, 'success');
}
/**
* 冻结余额
*/
private function freezeBalance($userId, $amount) {
$stmt = $this->db->prepare(
"UPDATE user_balances
SET balance = balance - ?,
frozen_amount = frozen_amount + ?,
updated_at = NOW()
WHERE user_id = ? AND balance >= ?"
);
$stmt->execute([$amount, $amount, $userId, $amount]);
if ($stmt->rowCount() === 0) {
throw new Exception("余额不足或更新失败");
}
}
/**
* 解冻余额
*/
private function unfreezeBalance($userId, $amount) {
$stmt = $this->db->prepare(
"UPDATE user_balances
SET balance = balance + ?,
frozen_amount = frozen_amount - ?,
updated_at = NOW()
WHERE user_id = ? AND frozen_amount >= ?"
);
$stmt->execute([$amount, $amount, $userId, $amount]);
}
/**
* 扣除冻结余额
*/
private function deductFrozenBalance($userId, $amount) {
$stmt = $this->db->prepare(
"UPDATE user_balances
SET frozen_amount = frozen_amount - ?,
updated_at = NOW()
WHERE user_id = ? AND frozen_amount >= ?"
);
$stmt->execute([$amount, $userId, $amount]);
}
/**
* 获取用户余额
*/
public function getUserBalance($userId) {
$stmt = $this->db->prepare("SELECT balance FROM user_balances WHERE user_id = ?");
$stmt->execute([$userId]);
$result = $stmt->fetch();
return $result ? $result['balance'] : 0;
}
/**
* 获取用户冻结金额
*/
public function getUserFrozenAmount($userId) {
$stmt = $this->db->prepare("SELECT frozen_amount FROM user_balances WHERE user_id = ?");
$stmt->execute([$userId]);
$result = $stmt->fetch();
return $result ? $result['frozen_amount'] : 0;
}
/**
* 计算手续费
*/
private function calculateFee($amount) {
return round($amount * $this->config['fee_rate'], 2);
}
/**
* 获取今日提现次数
*/
private function getTodayWithdrawalCount($userId) {
$stmt = $this->db->prepare(
"SELECT COUNT(*) FROM withdrawals
WHERE user_id = ?
AND DATE(created_at) = CURDATE()"
);
$stmt->execute([$userId]);
return $stmt->fetchColumn();
}
/**
* 获取今日提现金额
*/
private function getTodayWithdrawalAmount($userId) {
$stmt = $this->db->prepare(
"SELECT COALESCE(SUM(amount), 0) FROM withdrawals
WHERE user_id = ?
AND DATE(created_at) = CURDATE()"
);
$stmt->execute([$userId]);
return $stmt->fetchColumn();
}
/**
* 获取提现记录
*/
public function getWithdrawalById($id) {
$stmt = $this->db->prepare("SELECT * FROM withdrawals WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
/**
* 获取用户提现历史
*/
public function getUserWithdrawals($userId, $page = 1, $limit = 20) {
$offset = ($page - 1) * $limit;
$stmt = $this->db->prepare(
"SELECT * FROM withdrawals
WHERE user_id = ?
ORDER BY created_at DESC
LIMIT ? OFFSET ?"
);
$stmt->execute([$userId, $limit, $offset]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 获取所有提现记录(管理员)
*/
public function getAllWithdrawals($status = null, $page = 1, $limit = 20) {
$where = '';
$params = [];
if ($status) {
$where = "WHERE status = ?";
$params[] = $status;
}
$offset = ($page - 1) * $limit;
$stmt = $this->db->prepare(
"SELECT w.*, u.username
FROM withdrawals w
JOIN users u ON w.user_id = u.id
$where
ORDER BY w.created_at DESC
LIMIT ? OFFSET ?"
);
$params[] = $limit;
$params[] = $offset;
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
提现页面控制器
<?php
// controllers/WithdrawalController.php
class WithdrawalController {
private $withdrawalSystem;
private $user;
public function __construct($db, $userId) {
$this->withdrawalSystem = new WithdrawalSystem($db);
$this->user = $this->getUser($db, $userId);
}
/**
* 显示提现页面
*/
public function showWithdrawalForm() {
$balance = $this->withdrawalSystem->getUserBalance($this->user['id']);
$frozenAmount = $this->withdrawalSystem->getUserFrozenAmount($this->user['id']);
$availableBalance = $balance;
$config = require 'config/withdrawal.php';
$paymentMethods = $config['payment_methods'];
include 'views/withdrawal/form.php';
}
/**
* 处理提现申请
*/
public function submitWithdrawal() {
try {
$amount = floatval($_POST['amount']);
$paymentMethod = $_POST['payment_method'];
$accountInfo = [
'account' => $_POST['account'],
'name' => $_POST['account_name']
];
$withdrawalId = $this->withdrawalSystem->createWithdrawal(
$this->user['id'],
$amount,
$paymentMethod,
$accountInfo
);
$_SESSION['success'] = '提现申请提交成功,请等待审核';
} catch (Exception $e) {
$_SESSION['error'] = $e->getMessage();
}
header('Location: /withdrawal');
exit;
}
/**
* 提现历史
*/
public function showWithdrawalHistory() {
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$withdrawals = $this->withdrawalSystem->getUserWithdrawals($this->user['id'], $page);
include 'views/withdrawal/history.php';
}
}
提现表单视图
<!-- views/withdrawal/form.php -->
<div class="container">
<h2>提现申请</h2>
<?php if (isset($_SESSION['error'])): ?>
<div class="alert alert-danger"><?= $_SESSION['error'] ?></div>
<?php unset($_SESSION['error']); ?>
<?php endif; ?>
<?php if (isset($_SESSION['success'])): ?>
<div class="alert alert-success"><?= $_SESSION['success'] ?></div>
<?php unset($_SESSION['success']); ?>
<?php endif; ?>
<div class="balance-info">
<p>当前余额:<?= number_format($balance, 2) ?> 元</p>
<p>冻结金额:<?= number_format($frozenAmount, 2) ?> 元</p>
<p>可用余额:<?= number_format($availableBalance, 2) ?> 元</p>
</div>
<form action="/withdrawal/submit" method="POST">
<div class="form-group">
<label>提现金额</label>
<input type="number" name="amount" step="0.01"
min="<?= $config['min_amount'] ?>"
max="<?= $config['max_amount'] ?>"
required>
<small>最低提现金额:<?= $config['min_amount'] ?> 元</small>
</div>
<div class="form-group">
<label>支付方式</label>
<select name="payment_method" required>
<?php foreach ($paymentMethods as $key => $value): ?>
<option value="<?= $key ?>"><?= $value ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label>收款账号</label>
<input type="text" name="account" required>
</div>
<div class="form-group">
<label>收款人姓名</label>
<input type="text" name="account_name" required>
</div>
<button type="submit" class="btn btn-primary">提交提现申请</button>
</form>
</div>
管理员提现审核页面
<!-- views/admin/withdrawal/review.php -->
<div class="container">
<h2>提现审核管理</h2>
<div class="filter">
<form action="/admin/withdrawals" method="GET">
<select name="status">
<option value="pending">待审核</option>
<option value="processing">处理中</option>
<option value="success">已完成</option>
<option value="failed">已拒绝</option>
</select>
<button type="submit">筛选</button>
</form>
</div>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>用户</th>
<th>金额</th>
<th>手续费</th>
<th>实际到账</th>
<th>支付方式</th>
<th>状态</th>
<th>申请时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($withdrawals as $wd): ?>
<tr>
<td><?= $wd['id'] ?></td>
<td><?= htmlspecialchars($wd['username']) ?></td>
<td><?= number_format($wd['amount'], 2) ?></td>
<td><?= number_format($wd['fee'], 2) ?></td>
<td><?= number_format($wd['actual_amount'], 2) ?></td>
<td><?= $wd['payment_method'] ?></td>
<td>
<span class="badge badge-<?= $wd['status'] ?>">
<?= $wd['status'] ?>
</span>
</td>
<td><?= $wd['created_at'] ?></td>
<td>
<?php if ($wd['status'] == 'pending'): ?>
<button onclick="processWithdrawal(<?= $wd['id'] ?>, 'approve')">
审核通过
</button>
<button onclick="processWithdrawal(<?= $wd['id'] ?>, 'reject')">
拒绝
</button>
<?php elseif ($wd['status'] == 'processing'): ?>
<button onclick="processWithdrawal(<?= $wd['id'] ?>, 'complete')">
确认到账
</button>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<script>
function processWithdrawal(id, action) {
if (!confirm('确认执行此操作?')) return;
fetch('/admin/withdrawals/process', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
withdrawal_id: id,
action: action
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert(data.message);
}
});
}
</script>
路由配置
// routes/web.php
// 用户提现路由
Router::get('/withdrawal', 'WithdrawalController@showWithdrawalForm');
Router::post('/withdrawal/submit', 'WithdrawalController@submitWithdrawal');
Router::get('/withdrawal/history', 'WithdrawalController@showWithdrawalHistory');
// 管理员提现管理路由
Router::get('/admin/withdrawals', 'AdminWithdrawalController@index');
Router::post('/admin/withdrawals/process', 'AdminWithdrawalController@process');
Router::get('/admin/withdrawals/{id}', 'AdminWithdrawalController@detail');
安全注意事项
防止重复提交
// 添加CSRF令牌
session_start();
$_SESSION['withdrawal_token'] = bin2hex(random_bytes(32));
// 表单中添加
<input type="hidden" name="csrf_token" value="<?= $_SESSION['withdrawal_token'] ?>">
// 验证token
if ($_POST['csrf_token'] !== $_SESSION['withdrawal_token']) {
throw new Exception("安全验证失败");
}
金额验证
// 严格验证金额格式
if (!preg_match('/^\d+(\.\d{1,2})?$/', $amount)) {
throw new Exception("金额格式错误");
}
防刷机制
// 添加验证码 // 使用限流中间件
提现记录日志表
CREATE TABLE `withdrawal_logs` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `withdrawal_id` int(11) NOT NULL, `action` varchar(50) NOT NULL, `admin_id` int(11) DEFAULT NULL, `created_at` datetime NOT NULL, PRIMARY KEY (`id`), KEY `withdrawal_id` (`withdrawal_id`) );
这个提现系统包含了完整的业务流程、安全措施和防作弊机制,根据实际需求,你还可以:
- 添加多级审核流程
- 对接实际支付接口
- 实现自动打款功能
- 添加更详细的财务统计报表
- 实现提现风控系统
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播