本文目录导读:

我来帮你梳理PHP项目中用户数据导出与删除的完整实现方案。
用户数据导出功能
1 导出为CSV格式
<?php
// export_user_data.php
require_once 'config/database.php';
require_once 'classes/UserDataExport.php';
class UserDataExport {
private $db;
private $userId;
public function __construct($db, $userId) {
$this->db = $db;
$this->userId = $userId;
}
/**
* 导出用户所有数据
*/
public function exportAllData() {
$data = [
'profile' => $this->getProfile(),
'orders' => $this->getOrders(),
'messages' => $this->getMessages(),
'activity_logs' => $this->getActivityLogs(),
'comments' => $this->getComments()
];
return $data;
}
/**
* 导出为CSV文件
*/
public function exportToCSV() {
$data = $this->exportAllData();
// 设置headers
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="user_data_' . date('Y-m-d_H-i-s') . '.csv"');
// 创建输出流
$output = fopen('php://output', 'w');
// 添加BOM for UTF-8
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
// 导出个人信息
fputcsv($output, ['=== 个人信息 ===']);
fputcsv($output, ['字段', '值']);
foreach ($data['profile'] as $key => $value) {
fputcsv($output, [$key, $value]);
}
// 导出订单数据
fputcsv($output, []);
fputcsv($output, ['=== 订单记录 ===']);
fputcsv($output, ['订单ID', '金额', '状态', '创建时间']);
foreach ($data['orders'] as $order) {
fputcsv($output, [
$order['id'],
$order['amount'],
$order['status'],
$order['created_at']
]);
}
fclose($output);
exit;
}
/**
* 导出为JSON格式
*/
public function exportToJSON() {
$data = $this->exportAllData();
header('Content-Type: application/json; charset=utf-8');
header('Content-Disposition: attachment; filename="user_data_' . date('Y-m-d_H-i-s') . '.json"');
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
}
/**
* 导出为ZIP压缩包
*/
public function exportToZIP() {
$data = $this->exportAllData();
$tempDir = sys_get_temp_dir() . '/export_' . $this->userId . '_' . time();
// 创建临时目录
if (!is_dir($tempDir)) {
mkdir($tempDir, 0777, true);
}
// 写入各数据文件
file_put_contents($tempDir . '/profile.json', json_encode($data['profile'], JSON_UNESCAPED_UNICODE));
file_put_contents($tempDir . '/orders.json', json_encode($data['orders'], JSON_UNESCAPED_UNICODE));
file_put_contents($tempDir . '/messages.json', json_encode($data['messages'], JSON_UNESCAPED_UNICODE));
// 创建ZIP文件
$zipFile = sys_get_temp_dir() . '/user_data_' . $this->userId . '.zip';
$zip = new ZipArchive();
if ($zip->open($zipFile, ZipArchive::CREATE) === TRUE) {
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($tempDir),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $file) {
if (!$file->isDir()) {
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($tempDir) + 1);
$zip->addFile($filePath, $relativePath);
}
}
$zip->close();
// 下载ZIP文件
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="user_data_export.zip"');
header('Content-Length: ' . filesize($zipFile));
readfile($zipFile);
// 清理临时文件
array_map('unlink', glob("$tempDir/*.*"));
rmdir($tempDir);
unlink($zipFile);
}
exit;
}
private function getProfile() {
$stmt = $this->db->prepare("SELECT username, email, phone, created_at, last_login FROM users WHERE id = ?");
$stmt->execute([$this->userId]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
private function getOrders() {
$stmt = $this->db->prepare("SELECT id, amount, status, created_at FROM orders WHERE user_id = ?");
$stmt->execute([$this->userId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
private function getMessages() {
$stmt = $this->db->prepare("SELECT * FROM messages WHERE user_id = ?");
$stmt->execute([$this->userId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
private function getActivityLogs() {
$stmt = $this->db->prepare("SELECT * FROM activity_logs WHERE user_id = ? ORDER BY created_at DESC LIMIT 100");
$stmt->execute([$this->userId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
private function getComments() {
$stmt = $this->db->prepare("SELECT * FROM comments WHERE user_id = ?");
$stmt->execute([$this->userId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
2 导出页面界面
// export_page.php
<!DOCTYPE html>
<html>
<head>数据导出</title>
<style>
.export-container {
max-width: 600px;
margin: 50px auto;
padding: 30px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.export-options {
margin: 20px 0;
}
.export-btn {
display: inline-block;
padding: 10px 20px;
margin: 5px;
background: #007bff;
color: white;
text-decoration: none;
border-radius: 4px;
border: none;
cursor: pointer;
}
.export-btn:hover {
background: #0056b3;
}
.warning {
color: #856404;
background-color: #fff3cd;
border: 1px solid #ffeeba;
padding: 15px;
border-radius: 4px;
margin: 20px 0;
}
</style>
</head>
<body>
<div class="export-container">
<h2>导出我的数据</h2>
<div class="warning">
<strong>注意:</strong>导出的数据包含您的个人信息,请妥善保管。
</div>
<div class="export-options">
<h3>选择导出格式:</h3>
<a href="export.php?format=csv" class="export-btn">导出CSV</a>
<a href="export.php?format=json" class="export-btn">导出JSON</a>
<a href="export.php?format=zip" class="export-btn">导出ZIP压缩包</a>
</div>
<form method="POST" action="export.php">
<h3>选择性导出:</h3>
<label><input type="checkbox" name="data_types[]" value="profile" checked> 个人信息</label><br>
<label><input type="checkbox" name="data_types[]" value="orders" checked> 订单记录</label><br>
<label><input type="checkbox" name="data_types[]" value="messages" checked> 消息记录</label><br>
<label><input type="checkbox" name="data_types[]" value="comments" checked> 评论记录</label><br>
<button type="submit" name="export_custom" class="export-btn" style="margin-top: 15px;">导出选中数据</button>
</form>
</div>
</body>
</html>
用户数据删除功能
1 完整删除实现
<?php
// delete_user_data.php
require_once 'config/database.php';
require_once 'classes/UserDataDeletion.php';
class UserDataDeletion {
private $db;
private $userId;
private $logFile;
public function __construct($db, $userId) {
$this->db = $db;
$this->userId = $userId;
$this->logFile = 'deletion_logs.txt';
}
/**
* 软删除用户(标记删除)
*/
public function softDelete() {
try {
$this->db->beginTransaction();
// 标记用户为已删除
$stmt = $this->db->prepare("UPDATE users SET
status = 'deleted',
deleted_at = NOW(),
username = CONCAT('deleted_', id),
email = CONCAT('deleted_', id, '@removed.com')
WHERE id = ?");
$stmt->execute([$this->userId]);
// 匿名化相关数据
$this->anonymizeRelatedData();
$this->db->commit();
$this->logAction('soft_delete', 'User data anonymized and marked as deleted');
return true;
} catch (Exception $e) {
$this->db->rollBack();
$this->logAction('soft_delete_failed', $e->getMessage());
throw $e;
}
}
/**
* 硬删除用户(彻底删除)
*/
public function hardDelete() {
try {
$this->db->beginTransaction();
// 删除用户的所有数据
$tables = [
'user_sessions',
'password_resets',
'order_items',
'orders',
'comments',
'messages',
'activity_logs',
'user_meta',
'users'
];
foreach ($tables as $table) {
$this->deleteFromTable($table);
}
$this->db->commit();
$this->logAction('hard_delete', 'All user data permanently deleted');
return true;
} catch (Exception $e) {
$this->db->rollBack();
$this->logAction('hard_delete_failed', $e->getMessage());
throw $e;
}
}
/**
* 选择性删除特定数据
*/
public function selectiveDelete($dataTypes) {
try {
$this->db->beginTransaction();
$allowedTypes = ['orders', 'messages', 'comments', 'activity_logs'];
foreach ($dataTypes as $type) {
if (in_array($type, $allowedTypes)) {
$this->deleteFromTable($type);
}
}
$this->db->commit();
$this->logAction('selective_delete', 'Selected data types deleted: ' . implode(', ', $dataTypes));
return true;
} catch (Exception $e) {
$this->db->rollBack();
$this->logAction('selective_delete_failed', $e->getMessage());
throw $e;
}
}
/**
* 删除前备份用户数据
*/
public function backupBeforeDelete() {
$exporter = new UserDataExport($this->db, $this->userId);
$data = $exporter->exportAllData();
$backupFile = 'backups/user_' . $this->userId . '_' . date('Y-m-d_H-i-s') . '.json';
if (!is_dir('backups')) {
mkdir('backups', 0777, true);
}
file_put_contents($backupFile, json_encode($data, JSON_PRETTY_PRINT));
return $backupFile;
}
/**
* 带确认的删除流程
*/
public function deleteWithConfirmation($confirmationToken) {
// 验证确认令牌
if (!$this->validateConfirmationToken($confirmationToken)) {
throw new Exception('Invalid confirmation token');
}
// 备份数据
$backupFile = $this->backupBeforeDelete();
// 执行硬删除
$result = $this->hardDelete();
// 发送确认邮件
$this->sendDeletionConfirmationEmail($backupFile);
return $result;
}
private function deleteFromTable($table) {
$allowedTables = [
'user_sessions', 'password_resets', 'order_items',
'orders', 'comments', 'messages', 'activity_logs',
'user_meta', 'users'
];
if (!in_array($table, $allowedTables)) {
throw new Exception("Unauthorized table: $table");
}
$columnMap = [
'users' => 'id',
'user_sessions' => 'user_id',
'password_resets' => 'user_id',
'order_items' => 'user_id',
'orders' => 'user_id',
'comments' => 'user_id',
'messages' => 'user_id',
'activity_logs' => 'user_id',
'user_meta' => 'user_id'
];
$column = $columnMap[$table] ?? 'user_id';
$stmt = $this->db->prepare("DELETE FROM $table WHERE $column = ?");
$stmt->execute([$this->userId]);
return $stmt->rowCount();
}
private function anonymizeRelatedData() {
// 匿名化订单数据
$stmt = $this->db->prepare("UPDATE orders SET
shipping_address = 'REMOVED',
billing_address = 'REMOVED',
phone = 'REMOVED'
WHERE user_id = ?");
$stmt->execute([$this->userId]);
// 匿名化评论
$stmt = $this->db->prepare("UPDATE comments SET
content = '[This comment has been removed]'
WHERE user_id = ?");
$stmt->execute([$this->userId]);
// 删除会话
$stmt = $this->db->prepare("DELETE FROM user_sessions WHERE user_id = ?");
$stmt->execute([$this->userId]);
}
private function validateConfirmationToken($token) {
// 从数据库验证token
$stmt = $this->db->prepare("SELECT * FROM deletion_tokens
WHERE user_id = ? AND token = ? AND expires_at > NOW()");
$stmt->execute([$this->userId, $token]);
return $stmt->fetch() !== false;
}
private function sendDeletionConfirmationEmail($backupFile) {
$userEmail = $this->getUserEmail();
$subject = "Account Deletion Confirmation";
$message = "Your account has been successfully deleted.
If you need to recover your data, please contact support within 30 days.
Backup file: $backupFile";
// 邮件发送逻辑
mail($userEmail, $subject, $message);
}
private function getUserEmail() {
// 缓存用户邮箱用于最后通知
static $email = null;
if ($email === null) {
$stmt = $this->db->prepare("SELECT email FROM users WHERE id = ?");
$stmt->execute([$this->userId]);
$result = $stmt->fetch();
$email = $result ? $result['email'] : '';
}
return $email;
}
private function logAction($action, $details) {
$logEntry = date('Y-m-d H:i:s') . " - User ID: {$this->userId} - Action: $action - Details: $details\n";
file_put_contents($this->logFile, $logEntry, FILE_APPEND);
}
}
// 处理删除请求
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
session_start();
if (!isset($_SESSION['user_id'])) {
die('Unauthorized access');
}
$userId = $_SESSION['user_id'];
$deletion = new UserDataDeletion($db, $userId);
try {
if (isset($_POST['confirm_delete'])) {
// 发送确认邮件
$token = bin2hex(random_bytes(32));
// 保存token到数据库
// 发送确认邮件
$confirmLink = "http://example.com/confirm_delete.php?token=$token";
mail($userEmail, "Confirm Account Deletion", "Click to confirm: $confirmLink");
echo "Confirmation email sent. Please check your email to complete the deletion.";
} elseif (isset($_POST['soft_delete'])) {
$deletion->softDelete();
echo "Account has been deactivated. You can restore it within 30 days.";
} elseif (isset($_POST['hard_delete'])) {
$deletion->hardDelete();
echo "Account permanently deleted.";
session_destroy();
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
}
2 删除确认页面
// delete_account.php
<!DOCTYPE html>
<html>
<head>删除账户</title>
<style>
.delete-container {
max-width: 500px;
margin: 50px auto;
padding: 30px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.danger-zone {
border: 2px solid #dc3545;
border-radius: 8px;
padding: 20px;
margin: 20px 0;
}
.confirm-input {
width: 100%;
padding: 10px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 4px;
}
.btn-danger {
background: #dc3545;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.btn-danger:hover {
background: #c82333;
}
.options {
margin: 15px 0;
}
.option-item {
margin: 10px 0;
padding: 10px;
background: #f8f9fa;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="delete-container">
<h2>账户删除选项</h2>
<div class="danger-zone">
<h3>⚠️ 危险操作</h3>
<p>删除账户后,您将失去所有数据,此操作可能不可逆。</p>
</div>
<div class="options">
<div class="option-item">
<h4>选项1: 软删除(推荐)</h4>
<p>停用账户,数据被匿名化,您可以在30天内恢复。</p>
<form method="POST">
<button type="submit" name="soft_delete" class="btn btn-warning">
软删除账户
</button>
</form>
</div>
<div class="option-item">
<h4>选项2: 彻底删除</h4>
<p>永久删除所有数据,无法恢复。</p>
<form method="POST" onsubmit="return confirmDeletion()">
<label>请键入 "DELETE" 确认操作:</label>
<input type="text" class="confirm-input" id="confirm_text"
placeholder="输入 DELETE" required>
<button type="submit" name="hard_delete" class="btn-danger"
id="delete_btn" disabled>
彻底删除账户
</button>
</form>
</div>
<div class="option-item">
<h4>选项3: 选择性删除</h4>
<p>选择要删除的数据类型。</p>
<form method="POST">
<label><input type="checkbox" name="data_types[]" value="orders"> 删除订单记录</label><br>
<label><input type="checkbox" name="data_types[]" value="messages"> 删除消息记录</label><br>
<label><input type="checkbox" name="data_types[]" value="comments"> 删除评论</label><br>
<button type="submit" name="selective_delete" class="btn btn-secondary">
删除选定数据
</button>
</form>
</div>
</div>
<div class="data-export">
<h4>在删除前,建议您先导出数据</h4>
<a href="export.php" class="export-btn">导出我的数据</a>
</div>
</div>
<script>
function confirmDeletion() {
const confirmText = document.getElementById('confirm_text').value;
if (confirmText !== 'DELETE') {
alert('请正确输入 DELETE 确认删除');
return false;
}
return confirm('您确定要永久删除账户吗?此操作不可恢复!');
}
// 启用删除按钮当输入正确时
document.getElementById('confirm_text').addEventListener('input', function() {
document.getElementById('delete_btn').disabled = this.value !== 'DELETE';
});
</script>
</body>
</html>
定时清理任务
<?php
// cron/cleanup_deleted_users.php
/**
* 定时清理过期的软删除用户
* 建议运行:0 3 * * * php /path/to/cron/cleanup_deleted_users.php
*/
require_once '../config/database.php';
class DeletedUserCleanup {
private $db;
public function __construct($db) {
$this->db = $db;
}
public function cleanExpiredUsers() {
try {
$this->db->beginTransaction();
// 查找超过30天的软删除用户
$stmt = $this->db->prepare("
SELECT id, email, deleted_at
FROM users
WHERE status = 'deleted'
AND deleted_at <= DATE_SUB(NOW(), INTERVAL 30 DAY)
");
$stmt->execute();
$expiredUsers = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($expiredUsers as $user) {
$deletion = new UserDataDeletion($this->db, $user['id']);
$deletion->hardDelete();
echo "Permanently deleted user ID: {$user['id']}\n";
}
// 清理备份文件(超过90天)
$this->cleanOldBackups();
$this->db->commit();
echo "Cleanup completed. " . count($expiredUsers) . " users permanently deleted.\n";
} catch (Exception $e) {
$this->db->rollBack();
echo "Error during cleanup: " . $e->getMessage() . "\n";
}
}
private function cleanOldBackups() {
$backupDir = '../backups/';
$files = glob($backupDir . '*.json');
foreach ($files as $file) {
if (filemtime($file) < strtotime('-90 days')) {
unlink($file);
echo "Deleted old backup: $file\n";
}
}
}
}
// 执行清理
$cleanup = new DeletedUserCleanup($db);
$cleanup->cleanExpiredUsers();
数据库表结构
-- 用户表添加软删除字段
ALTER TABLE users ADD COLUMN status VARCHAR(20) DEFAULT 'active';
ALTER TABLE users ADD COLUMN deleted_at TIMESTAMP NULL;
-- 删除令牌表
CREATE TABLE IF NOT EXISTS deletion_tokens (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
token VARCHAR(64) NOT NULL,
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_token (user_id, token)
);
-- 删除日志表
CREATE TABLE IF NOT EXISTS deletion_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
action_type VARCHAR(50) NOT NULL,
details TEXT,
ip_address VARCHAR(45),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
安全建议
- 权限验证:确保只有用户本人或管理员可以操作
- 数据备份:删除前强制备份
- 多步确认:重要操作需要多重确认
- 日志记录:记录所有删除操作
- 冷却期:设置删除确认冷却期
- 速率限制:防止滥用删除功能
这个实现提供了完整的用户数据导出和删除功能,包括多种导出格式、软删除和硬删除选项,以及安全措施和定时清理任务。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播