HIGH 级别修复: - WebhookHandler: 添加 SSRF 防护 (Validator::is_valid_url) - AIGateway: 自定义端点添加 SSRF 验证 - AIGateway: 白名单域名匹配改为大小写不敏感 - CommercialManager: 文件读取添加路径遍历防护 (realpath) - GroupModel: from_array() 添加输入类型验证和清理 - GroupManager: add/remove_source_to_group 添加权限检查 MEDIUM 级别修复: - NotificationManager: 添加 5 分钟速率限制防止通知轰炸 - NotificationManager: 允许第三方扩展通知处理器 - EmailHandler: 添加收件人邮箱格式验证 - EmailHandler: 移除自定义 From 头避免 SPF/DKIM 问题 - CommercialManager: lock/unlock_version 添加权限检查 - CommercialManager: 商业插件列表支持过滤器扩展 - GroupManager: toggle 方法改进原子性,先更新分组再更新源 - AbstractAdapter: 正则匹配添加错误处理 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
199 lines
4.3 KiB
PHP
199 lines
4.3 KiB
PHP
<?php
|
|
/**
|
|
* 源分组数据模型
|
|
*
|
|
* @package WPBridge
|
|
*/
|
|
|
|
namespace WPBridge\SourceGroup;
|
|
|
|
// 防止直接访问
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* 源分组模型类
|
|
*/
|
|
class GroupModel {
|
|
|
|
/**
|
|
* 唯一标识
|
|
*
|
|
* @var string
|
|
*/
|
|
public string $id = '';
|
|
|
|
/**
|
|
* 分组名称
|
|
*
|
|
* @var string
|
|
*/
|
|
public string $name = '';
|
|
|
|
/**
|
|
* 分组描述
|
|
*
|
|
* @var string
|
|
*/
|
|
public string $description = '';
|
|
|
|
/**
|
|
* 包含的源 ID 列表
|
|
*
|
|
* @var array
|
|
*/
|
|
public array $source_ids = [];
|
|
|
|
/**
|
|
* 共享认证令牌
|
|
*
|
|
* @var string
|
|
*/
|
|
public string $shared_auth_token = '';
|
|
|
|
/**
|
|
* 是否启用
|
|
*
|
|
* @var bool
|
|
*/
|
|
public bool $enabled = true;
|
|
|
|
/**
|
|
* 创建时间
|
|
*
|
|
* @var string
|
|
*/
|
|
public string $created_at = '';
|
|
|
|
/**
|
|
* 更新时间
|
|
*
|
|
* @var string
|
|
*/
|
|
public string $updated_at = '';
|
|
|
|
/**
|
|
* 从数组创建实例
|
|
*
|
|
* @param array $data 数据数组
|
|
* @return self
|
|
*/
|
|
public static function from_array( array $data ): self {
|
|
$model = new self();
|
|
|
|
$model->id = sanitize_text_field( $data['id'] ?? '' );
|
|
$model->name = sanitize_text_field( $data['name'] ?? '' );
|
|
$model->description = sanitize_textarea_field( $data['description'] ?? '' );
|
|
|
|
// 验证 source_ids 为字符串数组
|
|
$source_ids = $data['source_ids'] ?? [];
|
|
if ( is_array( $source_ids ) ) {
|
|
$model->source_ids = array_values( array_filter(
|
|
array_map( 'sanitize_text_field', $source_ids ),
|
|
function ( $id ) {
|
|
return ! empty( $id ) && is_string( $id );
|
|
}
|
|
) );
|
|
}
|
|
|
|
$model->shared_auth_token = $data['shared_auth_token'] ?? '';
|
|
$model->enabled = (bool) ( $data['enabled'] ?? true );
|
|
$model->created_at = sanitize_text_field( $data['created_at'] ?? '' );
|
|
$model->updated_at = sanitize_text_field( $data['updated_at'] ?? '' );
|
|
|
|
return $model;
|
|
}
|
|
|
|
/**
|
|
* 转换为数组
|
|
*
|
|
* @param bool $include_sensitive 是否包含敏感字段
|
|
* @return array
|
|
*/
|
|
public function to_array( bool $include_sensitive = true ): array {
|
|
$data = [
|
|
'id' => $this->id,
|
|
'name' => $this->name,
|
|
'description' => $this->description,
|
|
'source_ids' => $this->source_ids,
|
|
'enabled' => $this->enabled,
|
|
'created_at' => $this->created_at,
|
|
'updated_at' => $this->updated_at,
|
|
];
|
|
|
|
$data['shared_auth_token'] = $include_sensitive
|
|
? $this->shared_auth_token
|
|
: ( empty( $this->shared_auth_token ) ? '' : '********' );
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* 验证模型
|
|
*
|
|
* @return array 错误数组
|
|
*/
|
|
public function validate(): array {
|
|
$errors = [];
|
|
|
|
if ( empty( $this->name ) ) {
|
|
$errors['name'] = __( '分组名称不能为空', 'wpbridge' );
|
|
}
|
|
|
|
return $errors;
|
|
}
|
|
|
|
/**
|
|
* 是否有效
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function is_valid(): bool {
|
|
return empty( $this->validate() );
|
|
}
|
|
|
|
/**
|
|
* 添加源到分组
|
|
*
|
|
* @param string $source_id 源 ID
|
|
*/
|
|
public function add_source( string $source_id ): void {
|
|
if ( ! in_array( $source_id, $this->source_ids, true ) ) {
|
|
$this->source_ids[] = $source_id;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 从分组移除源
|
|
*
|
|
* @param string $source_id 源 ID
|
|
*/
|
|
public function remove_source( string $source_id ): void {
|
|
$this->source_ids = array_values(
|
|
array_filter(
|
|
$this->source_ids,
|
|
fn( $id ) => $id !== $source_id
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 检查源是否在分组中
|
|
*
|
|
* @param string $source_id 源 ID
|
|
* @return bool
|
|
*/
|
|
public function has_source( string $source_id ): bool {
|
|
return in_array( $source_id, $this->source_ids, true );
|
|
}
|
|
|
|
/**
|
|
* 获取源数量
|
|
*
|
|
* @return int
|
|
*/
|
|
public function get_source_count(): int {
|
|
return count( $this->source_ids );
|
|
}
|
|
}
|