164 lines
No EOL
4.1 KiB
Markdown
164 lines
No EOL
4.1 KiB
Markdown
# 数据完整性指南
|
||
|
||
## 目录
|
||
|
||
- [防止意外数据丢失](#防止意外数据丢失)
|
||
- [删除前的验证](#删除前的验证)
|
||
- [考虑竞态条件](#考虑竞态条件)
|
||
- [基于会话的操作](#基于会话的操作)
|
||
- [如有疑问,及时询问](#如有疑问,及时询问)
|
||
- [数据操作安全清单](#数据操作安全清单)
|
||
- [需避免的常见陷阱](#需避免的常见陷阱)
|
||
|
||
## 防止意外数据丢失
|
||
|
||
在删除/修改前总是验证实体状态,以防止意外数据丢失。
|
||
|
||
### 删除前的验证
|
||
|
||
在删除或修改实体前,总是验证实体的状态。
|
||
|
||
#### 例子:删除草稿订单
|
||
|
||
```php
|
||
// 正确:删除前验证订单状态
|
||
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 ); // 可能会删除任何订单!
|
||
}
|
||
```
|
||
|
||
### 考虑竞争条件
|
||
|
||
思考是否可能出现影响错误数据的竞争条件。
|
||
|
||
#### 示例:用户特定数据删除
|
||
|
||
```php
|
||
// 良好:在删除前验证所有权
|
||
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 );
|
||
}
|
||
```
|
||
|
||
### 基于会话的操作
|
||
|
||
对于基于会话的操作(如购物车或结账),请验证会话所有权。
|
||
|
||
#### 例子:清除结账数据
|
||
|
||
```php
|
||
// 良好做法:验证会话所有权
|
||
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. 盲目信任用户输入
|
||
|
||
```php
|
||
// 错误示例
|
||
$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. 无需验证的批量操作
|
||
|
||
```php
|
||
// 错误:未经验证删除全部
|
||
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. 忽略返回值
|
||
|
||
```php
|
||
// 错误:未检查操作是否成功
|
||
$order->delete( true );
|
||
wp_send_json_success();
|
||
|
||
// 正确:检查结果
|
||
if ( $order->delete( true ) ) {
|
||
wp_send_json_success();
|
||
} else {
|
||
wp_send_json_error( '删除订单失败' );
|
||
}
|
||
``` |