4.1 KiB
4.1 KiB
数据完整性指南
目录
防止意外数据丢失
在删除/修改前总是验证实体状态,以防止意外数据丢失。
删除前的验证
在删除或修改实体前,总是验证实体的状态。
例子:删除草稿订单
// 正确:删除前验证订单状态
public function delete_draft_order( int $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order ) {
return false;
}
// 验证它确实是草稿或结账草稿
if ( ! in_array( $order->get_status(), array( 'draft', 'checkout-draft' ), true ) ) {
throw new \Exception( 'Cannot delete non-draft order' );
}
return $order->delete( true );
}
// 错误:没有验证
public function delete_draft_order( int $order_id ) {
$order = wc_get_order( $order_id );
return $order->delete( true ); // 可能会删除任何订单!
}
考虑竞争条件
思考是否可能出现影响错误数据的竞争条件。
示例:用户特定数据删除
// 良好:在删除前验证所有权
public function delete_user_cart_item( int $item_id, int $user_id ) {
$item = $this->get_cart_item( $item_id );
if ( ! $item ) {
return false;
}
// 防止竞争条件:验证项目属于此用户
if ( (int) $item->get_user_id() !== $user_id ) {
throw new \Exception( '无法删除属于其他用户的项目' );
}
return $this->data_store->delete( $item_id );
}
// 不良:可能存在竞争条件
public function delete_user_cart_item( int $item_id, int $user_id ) {
// 在此期间,其他用户可能已获取此项目
return $this->data_store->delete( $item_id );
}
基于会话的操作
对于基于会话的操作(如购物车或结账),请验证会话所有权。
例子:清除结账数据
// 良好做法:验证会话所有权
public function clear_checkout_data( int $session_id ) {
$current_session_id = WC()->session->get_customer_id();
if ( $session_id !== $current_session_id ) {
throw new \Exception( 'Cannot clear checkout data for another session' );
}
WC()->session->set( 'checkout_data', array() );
}
如有疑问,请询问
如果不确定数据操作,请澄清以下内容:
- 必需的州/所有权验证
- 软删除与硬删除的必需条件
- 防止删除的受保护州
数据操作安全检查清单
在实现修改或删除数据的代码前:
- 验证实体存在
- 验证实体状态(状态、类型等)
- 验证所有权(user_id、session_id 等)
- 检查竞态条件
- 考虑使用软删除(回收站)而非硬删除
- 添加适当的错误处理
- 记录敏感操作以供审计追踪
- 添加权限检查(
current_user_can())
常见陷阱与规避方法
1. 盲目信任用户输入
// 错误示例
$order_id = $_POST['order_id'];
$order->delete( true );
// 正确示例
$order_id = absint( $_POST['order_id'] );
if ( ! current_user_can( 'delete_order', $order_id ) ) {
wp_die( 'Unauthorized' );
}
// ... 执行其他验证 ...
2. 无需验证的批量操作
// 错误:未经验证删除全部
foreach ( $order_ids as $order_id ) {
wc_delete_order( $order_id );
}
// 正确:验证每个项目
foreach ( $order_ids as $order_id ) {
$order = wc_get_order( $order_id );
if ( $order && $order->get_status() === 'draft' ) {
wc_delete_order( $order_id );
}
}
3. 忽略返回值
// 错误:未检查操作是否成功
$order->delete( true );
wp_send_json_success();
// 正确:检查结果
if ( $order->delete( true ) ) {
wp_send_json_success();
} else {
wp_send_json_error( '删除订单失败' );
}