优化了一些问题

This commit is contained in:
2026-08-29 17:36:21 +08:00
parent 88eb29c645
commit af30159a03
6 changed files with 151 additions and 92 deletions
+8 -5
View File
@@ -73,13 +73,16 @@ class SchemaPermissions {
'download' => [
'key' => 'download',
'title' => '下载配置',
'version' => '1.0.0',
'version' => '1.1.0',
'option_key' => 'aksrt_download_config',
'groups' => [
['key' => 'basic', 'title' => '链接规则', 'fields' => [
['key' => 'url_alias', 'label' => '下载链接 URL 别名', 'type' => 'input', 'default' => 'download', 'required' => true, 'help' => '仅允许英文字母、数字、连字符和下划线;禁止中文、空格和 / \\ ? # & 等特殊符号。修改后旧别名路由立即失效,需重新获取下载地址。'],
['key' => 'default_max_uses', 'label' => '下载链接默认使用次数', 'type' => 'number', 'default' => 1, 'min' => 1, 'max' => 100, 'help' => '单个链接可完成下载的次数;文件完整送达后才计次(HEAD 探测、传输中断不计次)。耗尽后链接返回 410,需重新获取。'],
['key' => 'ttl_minutes', 'label' => '下载链接默认有效期限(分钟)', 'type' => 'number', 'default' => 10, 'min' => 1, 'max' => 1440, 'help' => '链接签发后超过该时长即失效并返回 410,不自动续期,需重新获取。'],
['key' => 'basic', 'title' => '下载总开关', 'fields' => [
['key' => 'enabled', 'label' => '启用本站下载链接', 'type' => 'switch', 'default' => true, 'help' => '总开关:开启后下载通过本站中转链接(别名、次数、有效期生效);关闭后下载按钮直接使用原始下载地址(直连),下方链接规则全部不生效,旧的中转链接同步失效。'],
]],
['key' => 'rules', 'title' => '链接规则', 'fields' => [
['key' => 'url_alias', 'label' => '下载链接 URL 别名', 'type' => 'input', 'default' => 'download', 'required' => true, 'dependsOn' => ['key' => 'enabled', 'value' => true], 'help' => '仅允许英文字母、数字、连字符和下划线;禁止中文、空格和 / \\ ? # & 等特殊符号。修改后旧别名路由立即失效,需重新获取下载地址。'],
['key' => 'default_max_uses', 'label' => '下载链接默认使用次数', 'type' => 'number', 'default' => 1, 'min' => 1, 'max' => 100, 'dependsOn' => ['key' => 'enabled', 'value' => true], 'help' => '单个链接可完成下载的次数;文件完整送达后才计次(HEAD 探测、传输中断不计次)。耗尽后链接返回 410,需重新获取。'],
['key' => 'ttl_minutes', 'label' => '下载链接默认有效期限(分钟)', 'type' => 'number', 'default' => 10, 'min' => 1, 'max' => 1440, 'dependsOn' => ['key' => 'enabled', 'value' => true], 'help' => '链接签发后超过该时长即失效并返回 410,不自动续期,需重新获取。'],
]],
],
],
+30 -66
View File
@@ -68,6 +68,19 @@ class Download {
));
}
/**
* Master switch for the site-routed download system (aksrt_download_config
* "enabled", default true). When off, download buttons render the raw
* source URLs directly and every token route/endpoint below stays dormant.
*/
public function is_enabled(): bool {
$cfg = get_option('aksrt_download_config', []);
if (!is_array($cfg)) {
return true;
}
return !isset($cfg['enabled']) || !empty($cfg['enabled']);
}
/**
* Effective download settings (aksrt_download_config), clamped so a
* corrupted option can never break routing or accounting.
@@ -97,6 +110,10 @@ class Download {
}
public function register_rewrite(): void {
if (!$this->is_enabled()) {
return;
}
add_rewrite_rule(
'^' . preg_quote($this->config()['endpoint'], '/') . '/([A-Za-z0-9]{1,64})/?$',
'index.php?' . self::QUERY_VAR . '=$matches[1]',
@@ -105,11 +122,12 @@ class Download {
}
/**
* Re-flush rewrite rules whenever the configured alias changes, using
* the same version-marker approach as Auth\Router.
* Re-flush rewrite rules whenever the configured alias or the master
* switch changes, using the same version-marker approach as Auth\Router.
*/
public function maybe_flush_rewrite(): void {
$version = AKSRT_VERSION . ':download-endpoint:' . $this->config()['endpoint'];
$endpoint = $this->is_enabled() ? $this->config()['endpoint'] : 'off';
$version = AKSRT_VERSION . ':download-endpoint:' . $endpoint;
if ((string) get_option('aksrt_dl_rewrite_version') !== $version) {
flush_rewrite_rules(false);
update_option('aksrt_dl_rewrite_version', $version);
@@ -122,17 +140,15 @@ class Download {
}
public function register_routes(): void {
if (!$this->is_enabled()) {
return;
}
register_rest_route('aksrt/v1', '/download/request', [
'methods' => 'POST',
'callback' => [$this, 'rest_request'],
'permission_callback' => [$this, 'check_rest_nonce'],
]);
register_rest_route('aksrt/v1', '/download/policy/(?P<id>\d+)', [
'methods' => 'GET',
'callback' => [$this, 'rest_policy'],
'permission_callback' => '__return_true',
]);
}
public function check_rest_nonce(\WP_REST_Request $request) {
@@ -155,63 +171,6 @@ class Download {
return true;
}
public function rest_policy(\WP_REST_Request $request) {
$post_id = (int) $request['id'];
$post = get_post($post_id);
if (!$post || !function_exists('aksrt_is_downloadable_content') || !aksrt_is_downloadable_content($post)) {
return new \WP_Error('aksrt_invalid', __('内容不存在或未启用下载能力', 'aksrt'), ['status' => 404]);
}
$meta = function_exists('aksrt_get_download_box_meta') ? aksrt_get_download_box_meta($post) : [];
$cost = aksrt_resource_download_cost($post);
$uid = get_current_user_id();
$priced = function_exists('aksrt_get_user_pay_price') ? aksrt_get_user_pay_price($post, $uid) : null;
$pay_modo = is_array($priced)
? ((($priced['modo'] ?? '0') === 'points') ? 'points' : '0')
: ((($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0');
$display_price = is_array($priced)
? ($priced['amount'] ?? ($pay_modo === 'points' ? 0 : '0.00'))
: (($pay_modo === 'points') ? (int) ($meta['points_price'] ?? 0) : (string) ($meta['price'] ?? '0.00'));
$access = class_exists('AKSRT\\Content\\Visibility')
? Visibility::get_post_access_state($post, $uid)
: [];
$need_captcha = function_exists('aksrt_is_captcha_enabled_for') && aksrt_is_captcha_enabled_for('download');
return new \WP_REST_Response([
'post_id' => $post_id,
'price' => $display_price,
'base_price' => is_array($priced) ? ($priced['base'] ?? $display_price) : $display_price,
'pay_modo' => $pay_modo,
'pay_limit' => (int) ($meta['pay_limit'] ?? 0),
'cost' => $cost,
'require_login' => !empty($access['need_login']),
'require_captcha' => $need_captcha,
'logged_in' => $uid > 0,
'balance' => $uid > 0 ? \AKSRT\Ledger\LedgerService::get_instance()->balance($uid, \AKSRT\Ledger\AssetType::POINTS) : 0,
'has_paid_access' => !empty($access['has_paid_access']),
'need_purchase' => !empty($access['need_purchase']),
'need_vip' => !empty($access['need_vip']),
'need_login' => !empty($access['need_login']) && $uid <= 0,
'can_download' => !empty($access['can_download']),
'login_url' => wp_login_url(get_permalink($post)),
'vip_level' => (int) ($access['user_vip_level'] ?? 0),
'free_limit' => $uid > 0 && function_exists('aksrt_get_user_free_download_limit') ? aksrt_get_user_free_download_limit($uid) : 0,
'free_used' => $uid > 0 && function_exists('aksrt_get_user_free_downloaded_number') ? aksrt_get_user_free_downloaded_number($uid) : 0,
'free_surplus' => $uid > 0 && function_exists('aksrt_get_free_download_surplus') ? aksrt_get_free_download_surplus($uid) : null,
'sources' => array_map(function ($row, $idx) {
$extract_code = trim((string) ($row['extract_code'] ?? ''));
return [
'index' => $idx,
'label' => $row['label'] ?? '',
'type' => $row['type'] ?? 'direct',
'has_extract' => $extract_code !== '',
];
}, $meta['downloads'] ?? [], array_keys($meta['downloads'] ?? [])),
], 200);
}
public function rest_request(\WP_REST_Request $request) {
$params = $request->get_json_params();
if (!is_array($params)) $params = $request->get_params();
@@ -303,6 +262,11 @@ class Download {
$this->fail_410();
}
// Master switch off: the token system is retired, links are dead ends.
if (!$this->is_enabled()) {
$this->fail_410();
}
global $wpdb;
$table = \AKSRT\Core\DBMigrator::table('dl_token');
if (!$table) $this->fail_410();