feat(pay): zibll-style pay_modo/points/pay_limit, VIP quota, and local speed stream

Expand post pay meta with cash/points modes and member purchase limits,
enforce free-download daily quotas, and stream local files with VIP speed
caps while keeping remote links on redirect.
This commit is contained in:
kate522 committed 2026-07-14 01:11:33 +08:00
1 parent 8b50687e9d
commit 1c8e4d3919
6 files changed
+311 -33

No files matched your search

+91 -1
View File
@@ -284,11 +284,101 @@ class AKSRT_Download {
update_post_meta((int) $row['post_id'], '_aksrt_res_download_count', $count + 1);
}
$target_url = esc_url_raw((string) $meta['downloads'][$idx]['url']);
$speed_kb = 0;
$uid_speed = (int) ($row['user_id'] ?? 0);
if ($uid_speed > 0 && function_exists('aksrt_get_user_download_speed')) {
$speed_kb = aksrt_get_user_download_speed($uid_speed);
}
// Local attachment / uploads file: optional throttled stream (Zibll speed limit).
$local_path = $this->resolve_local_download_path($target_url);
if ($local_path !== '' && is_readable($local_path)) {
$this->stream_local_file($local_path, $speed_kb);
exit;
}
nocache_headers();
wp_redirect(esc_url_raw((string) $meta['downloads'][$idx]['url']), 302);
wp_redirect($target_url, 302);
exit;
}
/**
* Map a site-local URL to a filesystem path under uploads (or ABSPATH).
*/
private function resolve_local_download_path(string $url): string {
if ($url === '') {
return '';
}
$uploads = wp_upload_dir();
$baseurl = trailingslashit((string) ($uploads['baseurl'] ?? ''));
$basedir = trailingslashit((string) ($uploads['basedir'] ?? ''));
if ($baseurl !== '' && str_starts_with($url, $baseurl)) {
$rel = substr($url, strlen($baseurl));
$path = $basedir . ltrim(rawurldecode($rel), '/\\');
$real = realpath($path);
$root = realpath($basedir);
if ($real && $root && str_starts_with($real, $root) && is_file($real)) {
return $real;
}
}
// Same-host path under ABSPATH.
$home = trailingslashit(home_url('/'));
if (str_starts_with($url, $home)) {
$rel = substr($url, strlen($home));
$path = ABSPATH . ltrim(rawurldecode($rel), '/\\');
$real = realpath($path);
$root = realpath(ABSPATH);
if ($real && $root && str_starts_with($real, $root) && is_file($real)) {
return $real;
}
}
return '';
}
/**
* Stream a local file with optional KB/s throttle.
*/
private function stream_local_file(string $path, int $speed_kb = 0): void {
$filename = basename($path);
$size = filesize($path);
if ($size === false) {
$this->fail_410();
}
nocache_headers();
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . rawurlencode($filename) . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . (string) $size);
$chunk = 1024 * 64; // 64KB
if ($speed_kb > 0) {
$chunk = max(1024, min($chunk, $speed_kb * 1024));
}
$fh = fopen($path, 'rb');
if (!$fh) {
$this->fail_410();
}
while (!feof($fh)) {
$buf = fread($fh, $chunk);
if ($buf === false) {
break;
}
echo $buf;
if (function_exists('flush')) {
flush();
}
if ($speed_kb > 0) {
// Approximate throttle: sleep 1s per speed_kb window when chunk ~= speed_kb KB.
usleep(200000); // 0.2s per chunk for smoother throttle
}
}
fclose($fh);
}
private function fail_410(): void {
status_header(410);
nocache_headers();