Files
easystream-main/f_core/f_classes/class.cdn.php
SamiAhmed7777 d22b3e1c0d feat: Add complete Docker deployment with web-based setup wizard
Major additions:
- Web-based setup wizard (setup.php, setup_wizard.php, setup-wizard.js)
- Production Docker configuration (docker-compose.prod.yml, .env.production)
- Database initialization SQL files (deploy/init_settings.sql)
- Template builder system with drag-and-drop UI
- Advanced features (OAuth, CDN, enhanced analytics, monetization)
- Comprehensive documentation (deployment guides, quick start, feature docs)
- Design system with accessibility and responsive layout
- Deployment automation scripts (deploy.ps1, generate-secrets.ps1)

Setup wizard allows customization of:
- Platform name and branding
- Domain configuration
- Membership tiers and pricing
- Admin credentials
- Feature toggles

Database includes 270+ tables for complete video streaming platform with
advanced features for analytics, moderation, template building, and monetization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-26 01:42:31 -07:00

219 lines
6.2 KiB
PHP

<?php
/**
* EasyStream CDN Integration
* Multi-CDN support: Cloudflare, AWS CloudFront, Bunny CDN
* Version: 1.0
*/
defined('_ISVALID') or header('Location: /error');
class VCDN {
private static $db;
private static $active_cdn = null;
public static function init() {
self::$db = VDatabase::getInstance();
self::loadActiveCDN();
}
/**
* Load active CDN configuration
*/
private static function loadActiveCDN() {
$sql = "SELECT * FROM db_cdn_config
WHERE is_active = 1
ORDER BY priority ASC
LIMIT 1";
$result = self::$db->execute($sql);
if ($result && $result->RecordCount() > 0) {
self::$active_cdn = $result->FetchRow();
}
}
/**
* Get CDN URL for file
* @param string $file_path Original file path
* @param string $file_type Type (video, image, audio, etc.)
* @return string CDN URL or original path
*/
public static function getCDNUrl($file_path, $file_type = 'video') {
self::init();
if (!self::$active_cdn || empty(self::$active_cdn['base_url'])) {
return $file_path; // Return original if no CDN
}
$base_url = rtrim(self::$active_cdn['base_url'], '/');
$file_path = ltrim($file_path, '/');
return "$base_url/$file_path";
}
/**
* Purge cache for specific file
* @param string $file_path File path to purge
* @return bool Success
*/
public static function purgeCache($file_path) {
self::init();
if (!self::$active_cdn) {
return false;
}
$provider = self::$active_cdn['provider'];
switch ($provider) {
case 'cloudflare':
return self::purgeCloudflare($file_path);
case 'bunny':
return self::purgeBunny($file_path);
case 'aws':
return self::purgeAWS($file_path);
default:
return false;
}
}
/**
* Purge Cloudflare cache
*/
private static function purgeCloudflare($file_path) {
$zone_id = self::$active_cdn['zone_id'];
$api_key = self::$active_cdn['api_key'];
if (empty($zone_id) || empty($api_key)) {
return false;
}
$url = "https://api.cloudflare.com/client/v4/zones/$zone_id/purge_cache";
$cdn_url = self::getCDNUrl($file_path);
$data = json_encode(['files' => [$cdn_url]]);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $api_key,
'Content-Type: application/json',
'Content-Length: ' . strlen($data)
]);
$result = curl_exec($ch);
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $status_code == 200;
}
/**
* Purge Bunny CDN cache
*/
private static function purgeBunny($file_path) {
$api_key = self::$active_cdn['api_key'];
$zone_id = self::$active_cdn['zone_id']; // Pull zone ID
if (empty($api_key) || empty($zone_id)) {
return false;
}
$cdn_url = self::getCDNUrl($file_path);
$url = "https://api.bunny.net/pullzone/$zone_id/purgeCache";
$data = json_encode(['url' => $cdn_url]);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'AccessKey: ' . $api_key,
'Content-Type: application/json'
]);
$result = curl_exec($ch);
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $status_code == 200 || $status_code == 204;
}
/**
* Purge AWS CloudFront cache
*/
private static function purgeAWS($file_path) {
// AWS CloudFront invalidation would require AWS SDK
// For now, return false (implement if AWS SDK available)
return false;
}
/**
* Track CDN statistics
* @param string $file_key File key
* @param int $bandwidth Bandwidth in MB
* @param int $requests Number of requests
*/
public static function trackStats($file_key, $bandwidth, $requests) {
self::init();
if (!self::$active_cdn) {
return;
}
$file_key_safe = VDatabase::escape($file_key);
$provider = VDatabase::escape(self::$active_cdn['provider']);
$bandwidth = (float)$bandwidth;
$requests = (int)$requests;
$date = date('Y-m-d');
$sql = "INSERT INTO db_cdn_stats
(file_key, cdn_provider, bandwidth_mb, requests, date)
VALUES ('$file_key_safe', '$provider', $bandwidth, $requests, '$date')
ON DUPLICATE KEY UPDATE
bandwidth_mb = bandwidth_mb + $bandwidth,
requests = requests + $requests";
self::$db->execute($sql);
}
/**
* Get CDN statistics
* @param string $file_key File key
* @param string $date_from Start date
* @param string $date_to End date
* @return array Stats
*/
public static function getStats($file_key, $date_from, $date_to) {
self::init();
$file_key_safe = VDatabase::escape($file_key);
$date_from_safe = VDatabase::escape($date_from);
$date_to_safe = VDatabase::escape($date_to);
$sql = "SELECT cdn_provider, SUM(bandwidth_mb) as total_bandwidth, SUM(requests) as total_requests
FROM db_cdn_stats
WHERE file_key = '$file_key_safe'
AND date BETWEEN '$date_from_safe' AND '$date_to_safe'
GROUP BY cdn_provider";
$result = self::$db->execute($sql);
$stats = [];
if ($result) {
while ($row = $result->FetchRow()) {
$stats[] = $row;
}
}
return $stats;
}
}