本文目录导读:

在 PHP 中实现数据删除验证,通常涉及以下几个层面,我来详细介绍各种验证方法和最佳实践:
基础权限验证
用户身份验证
<?php
session_start();
// 验证用户是否登录
function checkLogin() {
if (!isset($_SESSION['user_id'])) {
die(json_encode(['error' => '未登录,请先登录']));
}
return $_SESSION['user_id'];
}
// 验证用户是否有删除权限
function checkPermission($user_id, $required_permission) {
$pdo = getPDO();
$stmt = $pdo->prepare("
SELECT permission_name
FROM user_permissions
WHERE user_id = ? AND permission_name = ?
");
$stmt->execute([$user_id, $required_permission]);
return $stmt->fetch() !== false;
}
验证请求方法
<?php
// 确保只允许 POST 或 DELETE 请求
function validateRequestMethod($method = 'POST') {
if ($_SERVER['REQUEST_METHOD'] !== $method) {
http_response_code(405);
die(json_encode(['error' => '请求方法不允许']));
}
}
// 使用方法
validateRequestMethod('POST');
// 或
validateRequestMethod('DELETE');
CSRF 令牌验证
<?php
session_start();
// 生成 CSRF 令牌
function generateCSRFToken() {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
// 验证 CSRF 令牌
function verifyCSRFToken($token) {
if (!isset($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $token)) {
die(json_encode(['error' => 'CSRF 验证失败']));
}
}
// 使用示例
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$csrf_token = $_POST['csrf_token'] ?? '';
verifyCSRFToken($csrf_token);
}
数据存在性验证
<?php
// 验证要删除的数据是否存在
function validateDataExists($table, $id) {
$pdo = getPDO();
// 验证 ID 格式
if (!filter_var($id, FILTER_VALIDATE_INT) || $id <= 0) {
die(json_encode(['error' => '无效的 ID']));
}
// 验证数据是否存在
$stmt = $pdo->prepare("SELECT id FROM {$table} WHERE id = ?");
$stmt->execute([$id]);
if (!$stmt->fetch()) {
die(json_encode(['error' => '要删除的数据不存在']));
}
return $id;
}
关联数据验证
<?php
// 检查是否有关联数据
function checkRelatedData($check_array) {
$pdo = getPDO();
foreach ($check_array as $check) {
$stmt = $pdo->prepare("SELECT COUNT(*) FROM {$check['table']} WHERE {$check['column']} = ?");
$stmt->execute([$check['value']]);
if ($stmt->fetchColumn() > 0) {
die(json_encode([
'error' => '无法删除,存在关联数据',
'related_table' => $check['table']
]));
}
}
}
// 使用示例
$checks = [
['table' => 'orders', 'column' => 'user_id', 'value' => $user_id],
['table' => 'reviews', 'column' => 'user_id', 'value' => $user_id]
];
checkRelatedData($checks);
完整删除验证流程示例
<?php
class DataDeletionValidator {
private $pdo;
public function __construct($pdo) {
$this->pdo = $pdo;
}
/**
* 完整的删除验证流程
*/
public function validate($table, $id, $user_id, $options = []) {
// 1. 验证用户登录
if (!$user_id) {
throw new Exception('用户未登录', 401);
}
// 2. 验证请求方法
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
throw new Exception('请求方法不允许', 405);
}
// 3. 验证 CSRF
if (isset($options['csrf']) && !verifyCSRFToken($_POST['csrf_token'])) {
throw new Exception('CSRF 验证失败', 403);
}
// 4. 验证 ID 格式
if (!is_numeric($id) || $id <= 0) {
throw new Exception('无效的数据 ID', 400);
}
// 5. 验证数据存在性
$stmt = $this->pdo->prepare("SELECT * FROM {$table} WHERE id = ?");
$stmt->execute([$id]);
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$data) {
throw new Exception('数据不存在', 404);
}
// 6. 验证数据所有权(如果是用户数据)
if (isset($options['owner_column'])) {
$owner_column = $options['owner_column'];
if ($data[$owner_column] != $user_id) {
throw new Exception('没有权限删除此数据', 403);
}
}
// 7. 验证关联数据(避免外键约束冲突)
if (isset($options['related'])) {
foreach ($options['related'] as $related) {
$stmt = $this->pdo->prepare(
"SELECT COUNT(*) FROM {$related['table']} WHERE {$related['column']} = ?"
);
$stmt->execute([$id]);
if ($stmt->fetchColumn() > 0) {
throw new Exception(
"无法删除,存在关联数据在 {$related['table']} 表中",
409
);
}
}
}
return true;
}
}
// 使用示例
try {
$validator = new DataDeletionValidator(getPDO());
// 验证删除用户
$validator->validate(
'users',
$_POST['user_id'],
$_SESSION['user_id'],
[
'csrf' => true,
'owner_column' => 'id', // 管理员可以删除任何用户,这里需要特殊处理
// 或者可以检查是否为管理员
]
);
// 验证删除文章
$validator->validate(
'posts',
$_POST['post_id'],
$_SESSION['user_id'],
[
'csrf' => true,
'owner_column' => 'author_id',
'related' => [
['table' => 'comments', 'column' => 'post_id']
]
]
);
// 执行删除操作
$stmt = $pdo->prepare("DELETE FROM posts WHERE id = ?");
$stmt->execute([$_POST['post_id']]);
echo json_encode(['success' => true, 'message' => '删除成功']);
} catch (Exception $e) {
http_response_code($e->getCode());
echo json_encode(['error' => $e->getMessage()]);
}
注意事项
软删除 vs 硬删除
<?php
// 软删除(推荐)
function softDelete($table, $id) {
$stmt = $pdo->prepare(
"UPDATE {$table} SET deleted_at = NOW(), deleted_by = ? WHERE id = ?"
);
$stmt->execute([$_SESSION['user_id'], $id]);
return true;
}
// 硬删除
function hardDelete($table, $id) {
$stmt = $pdo->prepare("DELETE FROM {$table} WHERE id = ?");
$stmt->execute([$id]);
return true;
}
操作日志记录
<?php
// 记录删除操作日志
function logDeletion($table, $id, $user_id, $details = '') {
$stmt = $pdo->prepare("
INSERT INTO deletion_logs (table_name, record_id, user_id, details, created_at)
VALUES (?, ?, ?, ?, NOW())
");
$stmt->execute([$table, $id, $user_id, $details]);
}
最佳实践建议
- 总是验证:不要跳过任何验证步骤
- 使用参数化查询:防止 SQL 注入
- 实现软删除:比硬删除更安全
- 记录操作日志:便于审计和追踪
- 返回明确的错误信息:帮助用户理解问题
- 使用事务:确保数据一致性
- 考虑并发情况:防止并发删除问题
完整的前后端配合示例
<!-- 前端 HTML 表单 -->
<form id="deleteForm" method="POST">
<input type="hidden" name="csrf_token" value="<?= generateCSRFToken() ?>">
<input type="hidden" name="data_id" value="<?= $item_id ?>">
<input type="hidden" name="confirm" value="1">
<div class="delete-confirmation">
<p>确定要删除这条记录吗?此操作不可恢复!</p>
<button type="submit" class="btn-danger">确认删除</button>
<button type="button" class="btn-cancel">取消</button>
</div>
</form>
<script>
document.getElementById('deleteForm').addEventListener('submit', function(e) {
e.preventDefault();
if (!confirm('确定要删除吗?此操作不可恢复!')) {
return;
}
fetch(this.action, {
method: 'POST',
body: new FormData(this)
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('删除成功');
window.location.href = '/list';
} else {
alert(data.error);
}
});
});
</script>
通过以上多层验证机制,可以确保 PHP 中的数据删除操作安全可靠,防止未授权访问和误操作。