Files
easystream-main/f_core/f_classes/class.analytics.php
SamiAhmed7777 0b7e2d0a5b feat: Add comprehensive documentation suite and reorganize project structure
- Created complete documentation in docs/ directory
- Added PROJECT_OVERVIEW.md with feature highlights and getting started guide
- Added ARCHITECTURE.md with system design and technical details
- Added SECURITY.md with comprehensive security implementation guide
- Added DEVELOPMENT.md with development workflows and best practices
- Added DEPLOYMENT.md with production deployment instructions
- Added API.md with complete REST API documentation
- Added CONTRIBUTING.md with contribution guidelines
- Added CHANGELOG.md with version history and migration notes
- Reorganized all documentation files into docs/ directory for better organization
- Updated README.md with proper documentation links and quick navigation
- Enhanced project structure with professional documentation standards
2025-10-21 00:39:45 -07:00

690 lines
23 KiB
PHP

<?php
/*******************************************************************************************************************
| Software Name : EasyStream
| Software Description : High End YouTube Clone Script with Videos, Shorts, Streams, Images, Audio, Documents, Blogs
| Software Author : (c) Sami Ahmed
|*******************************************************************************************************************
|
|*******************************************************************************************************************
| This source file is subject to the EasyStream Proprietary License Agreement.
|
| By using this software, you acknowledge having read this Agreement and agree to be bound thereby.
|*******************************************************************************************************************
| Copyright (c) 2025 Sami Ahmed. All rights reserved.
|*******************************************************************************************************************/
defined('_ISVALID') or header('Location: /error');
/**
* Advanced Analytics System for Platform Metrics and Reporting
*/
class VAnalytics
{
private $db;
private $logger;
private $cache;
private $rbac;
public function __construct()
{
$this->db = VDatabase::getInstance();
$this->logger = VLogger::getInstance();
$this->cache = VRedis::getInstance();
$this->rbac = VRBAC::getInstance();
}
/**
* Get platform overview statistics
* @param array $filters Date range and other filters
* @return array Platform statistics
*/
public function getPlatformOverview($filters = [])
{
$dateRange = $this->getDateRange($filters);
$cacheKey = "analytics_overview_" . md5(serialize($filters));
// Try cache first
if ($this->cache->isConnected()) {
$cached = $this->cache->get($cacheKey);
if ($cached !== false) {
return $cached;
}
}
try {
$overview = [
'users' => $this->getUserStatistics($dateRange),
'content' => $this->getContentStatistics($dateRange),
'engagement' => $this->getEngagementStatistics($dateRange),
'streaming' => $this->getStreamingStatistics($dateRange),
'revenue' => $this->getRevenueStatistics($dateRange),
'performance' => $this->getPerformanceStatistics($dateRange),
'growth' => $this->getGrowthStatistics($dateRange)
];
// Cache for 15 minutes
if ($this->cache->isConnected()) {
$this->cache->set($cacheKey, $overview, 900);
}
return $overview;
} catch (Exception $e) {
$this->logger->error('Failed to get platform overview', [
'error' => $e->getMessage(),
'filters' => $filters
]);
return [];
}
}
/**
* Get user analytics
* @param int $userId User ID
* @param array $filters Filters
* @return array User analytics
*/
public function getUserAnalytics($userId, $filters = [])
{
// Check permissions
if (!$this->rbac->hasPermission($userId, 'analytics.view')) {
throw new Exception('User does not have analytics permission');
}
$dateRange = $this->getDateRange($filters);
$cacheKey = "user_analytics_{$userId}_" . md5(serialize($filters));
// Try cache first
if ($this->cache->isConnected()) {
$cached = $this->cache->get($cacheKey);
if ($cached !== false) {
return $cached;
}
}
try {
$analytics = [
'overview' => $this->getUserOverview($userId, $dateRange),
'videos' => $this->getUserVideoAnalytics($userId, $dateRange),
'audience' => $this->getUserAudienceAnalytics($userId, $dateRange),
'engagement' => $this->getUserEngagementAnalytics($userId, $dateRange),
'revenue' => $this->getUserRevenueAnalytics($userId, $dateRange),
'growth' => $this->getUserGrowthAnalytics($userId, $dateRange)
];
// Cache for 10 minutes
if ($this->cache->isConnected()) {
$this->cache->set($cacheKey, $analytics, 600);
}
return $analytics;
} catch (Exception $e) {
$this->logger->error('Failed to get user analytics', [
'user_id' => $userId,
'error' => $e->getMessage(),
'filters' => $filters
]);
return [];
}
}
/**
* Get video analytics
* @param string $videoKey Video key
* @param int $userId User ID (for permission check)
* @param array $filters Filters
* @return array Video analytics
*/
public function getVideoAnalytics($videoKey, $userId, $filters = [])
{
// Check if user owns video or has permission
if (!$this->canViewVideoAnalytics($videoKey, $userId)) {
throw new Exception('Permission denied');
}
$dateRange = $this->getDateRange($filters);
$cacheKey = "video_analytics_{$videoKey}_" . md5(serialize($filters));
// Try cache first
if ($this->cache->isConnected()) {
$cached = $this->cache->get($cacheKey);
if ($cached !== false) {
return $cached;
}
}
try {
$analytics = [
'overview' => $this->getVideoOverview($videoKey, $dateRange),
'views' => $this->getVideoViewAnalytics($videoKey, $dateRange),
'engagement' => $this->getVideoEngagementAnalytics($videoKey, $dateRange),
'audience' => $this->getVideoAudienceAnalytics($videoKey, $dateRange),
'performance' => $this->getVideoPerformanceAnalytics($videoKey, $dateRange),
'retention' => $this->getVideoRetentionAnalytics($videoKey, $dateRange)
];
// Cache for 5 minutes
if ($this->cache->isConnected()) {
$this->cache->set($cacheKey, $analytics, 300);
}
return $analytics;
} catch (Exception $e) {
$this->logger->error('Failed to get video analytics', [
'video_key' => $videoKey,
'user_id' => $userId,
'error' => $e->getMessage(),
'filters' => $filters
]);
return [];
}
}
/**
* Track video view
* @param string $videoKey Video key
* @param array $viewData View data
* @return bool Success status
*/
public function trackVideoView($videoKey, $viewData)
{
try {
$trackingData = [
'video_key' => $videoKey,
'user_id' => $viewData['user_id'] ?? null,
'ip_address' => $viewData['ip_address'] ?? $_SERVER['REMOTE_ADDR'],
'user_agent' => $viewData['user_agent'] ?? $_SERVER['HTTP_USER_AGENT'],
'referrer' => $viewData['referrer'] ?? $_SERVER['HTTP_REFERER'] ?? '',
'country' => $viewData['country'] ?? $this->getCountryFromIP($viewData['ip_address'] ?? $_SERVER['REMOTE_ADDR']),
'device_type' => $viewData['device_type'] ?? $this->getDeviceType($_SERVER['HTTP_USER_AGENT'] ?? ''),
'watch_duration' => $viewData['watch_duration'] ?? 0,
'quality' => $viewData['quality'] ?? 'auto',
'created_at' => date('Y-m-d H:i:s')
];
$this->db->doInsert('db_video_analytics', $trackingData);
// Update video view count
$this->db->doQuery("UPDATE db_videofiles SET file_views = file_views + 1 WHERE file_key = ?", [$videoKey]);
// Queue analytics processing job
$queue = new VQueue();
$queue->enqueue('AnalyticsProcessingJob', [
'type' => 'video_view',
'video_key' => $videoKey,
'data' => $trackingData
], 'analytics');
return true;
} catch (Exception $e) {
$this->logger->error('Failed to track video view', [
'video_key' => $videoKey,
'error' => $e->getMessage()
]);
return false;
}
}
/**
* Track user engagement
* @param string $eventType Event type (like, comment, share, etc.)
* @param array $eventData Event data
* @return bool Success status
*/
public function trackEngagement($eventType, $eventData)
{
try {
$trackingData = [
'event_type' => $eventType,
'user_id' => $eventData['user_id'] ?? null,
'target_type' => $eventData['target_type'] ?? 'video',
'target_id' => $eventData['target_id'] ?? '',
'ip_address' => $eventData['ip_address'] ?? $_SERVER['REMOTE_ADDR'],
'user_agent' => $eventData['user_agent'] ?? $_SERVER['HTTP_USER_AGENT'],
'data' => json_encode($eventData['additional_data'] ?? []),
'created_at' => date('Y-m-d H:i:s')
];
$this->db->doInsert('db_engagement_analytics', $trackingData);
// Queue analytics processing job
$queue = new VQueue();
$queue->enqueue('AnalyticsProcessingJob', [
'type' => 'engagement',
'event_type' => $eventType,
'data' => $trackingData
], 'analytics');
return true;
} catch (Exception $e) {
$this->logger->error('Failed to track engagement', [
'event_type' => $eventType,
'error' => $e->getMessage()
]);
return false;
}
}
/**
* Get real-time statistics
* @return array Real-time stats
*/
public function getRealTimeStats()
{
$cacheKey = "realtime_stats";
// Try cache first (very short cache)
if ($this->cache->isConnected()) {
$cached = $this->cache->get($cacheKey);
if ($cached !== false) {
return $cached;
}
}
try {
$stats = [
'active_users' => $this->getActiveUsers(),
'live_streams' => $this->getLiveStreamCount(),
'current_viewers' => $this->getCurrentViewers(),
'recent_uploads' => $this->getRecentUploads(),
'server_load' => $this->getServerLoad(),
'bandwidth_usage' => $this->getBandwidthUsage()
];
// Cache for 30 seconds
if ($this->cache->isConnected()) {
$this->cache->set($cacheKey, $stats, 30);
}
return $stats;
} catch (Exception $e) {
$this->logger->error('Failed to get real-time stats', [
'error' => $e->getMessage()
]);
return [];
}
}
/**
* Generate analytics report
* @param string $reportType Report type
* @param array $parameters Report parameters
* @param int $userId User ID (for permission check)
* @return array Report data
*/
public function generateReport($reportType, $parameters, $userId)
{
// Check permissions
if (!$this->rbac->hasPermission($userId, 'analytics.reports')) {
throw new Exception('User does not have report generation permission');
}
try {
switch ($reportType) {
case 'user_growth':
return $this->generateUserGrowthReport($parameters);
case 'content_performance':
return $this->generateContentPerformanceReport($parameters);
case 'engagement_trends':
return $this->generateEngagementTrendsReport($parameters);
case 'revenue_analysis':
return $this->generateRevenueAnalysisReport($parameters);
case 'platform_health':
return $this->generatePlatformHealthReport($parameters);
default:
throw new Exception("Unknown report type: {$reportType}");
}
} catch (Exception $e) {
$this->logger->error('Failed to generate report', [
'report_type' => $reportType,
'user_id' => $userId,
'error' => $e->getMessage()
]);
throw $e;
}
}
/**
* Get user statistics
* @param array $dateRange Date range
* @return array User statistics
*/
private function getUserStatistics($dateRange)
{
$query = "SELECT
COUNT(*) as total_users,
COUNT(CASE WHEN usr_status = 'active' THEN 1 END) as active_users,
COUNT(CASE WHEN DATE(usr_joindate) >= ? THEN 1 END) as new_users,
COUNT(CASE WHEN usr_lastlogin >= ? THEN 1 END) as recent_active
FROM db_accountuser
WHERE usr_joindate <= ?";
$result = $this->db->doQuery($query, [
$dateRange['start'],
$dateRange['start'],
$dateRange['end']
]);
return $this->db->doFetch($result) ?: [];
}
/**
* Get content statistics
* @param array $dateRange Date range
* @return array Content statistics
*/
private function getContentStatistics($dateRange)
{
$query = "SELECT
COUNT(*) as total_videos,
COUNT(CASE WHEN DATE(upload_date) >= ? THEN 1 END) as new_videos,
SUM(file_views) as total_views,
SUM(CASE WHEN DATE(upload_date) >= ? THEN file_views ELSE 0 END) as period_views,
AVG(file_rating) as average_rating,
SUM(file_size) as total_storage
FROM db_videofiles
WHERE upload_date <= ? AND file_type = 'video'";
$result = $this->db->doQuery($query, [
$dateRange['start'],
$dateRange['start'],
$dateRange['end']
]);
return $this->db->doFetch($result) ?: [];
}
/**
* Get engagement statistics
* @param array $dateRange Date range
* @return array Engagement statistics
*/
private function getEngagementStatistics($dateRange)
{
$query = "SELECT
COUNT(CASE WHEN event_type = 'like' THEN 1 END) as total_likes,
COUNT(CASE WHEN event_type = 'comment' THEN 1 END) as total_comments,
COUNT(CASE WHEN event_type = 'share' THEN 1 END) as total_shares,
COUNT(CASE WHEN event_type = 'subscribe' THEN 1 END) as total_subscriptions
FROM db_engagement_analytics
WHERE created_at BETWEEN ? AND ?";
$result = $this->db->doQuery($query, [
$dateRange['start'],
$dateRange['end']
]);
return $this->db->doFetch($result) ?: [];
}
/**
* Get streaming statistics
* @param array $dateRange Date range
* @return array Streaming statistics
*/
private function getStreamingStatistics($dateRange)
{
$query = "SELECT
COUNT(*) as total_streams,
COUNT(CASE WHEN status = 'live' THEN 1 END) as live_streams,
SUM(max_viewers) as total_max_viewers,
AVG(max_viewers) as avg_max_viewers,
SUM(duration) as total_duration
FROM db_live_streams
WHERE created_at BETWEEN ? AND ?";
$result = $this->db->doQuery($query, [
$dateRange['start'],
$dateRange['end']
]);
return $this->db->doFetch($result) ?: [];
}
/**
* Get revenue statistics
* @param array $dateRange Date range
* @return array Revenue statistics
*/
private function getRevenueStatistics($dateRange)
{
// This would integrate with your monetization system
return [
'total_revenue' => 0,
'period_revenue' => 0,
'transactions' => 0,
'average_transaction' => 0
];
}
/**
* Get performance statistics
* @param array $dateRange Date range
* @return array Performance statistics
*/
private function getPerformanceStatistics($dateRange)
{
// Get from job statistics and system metrics
$query = "SELECT
COUNT(*) as total_jobs,
COUNT(CASE WHEN status = 'completed' THEN 1 END) as completed_jobs,
COUNT(CASE WHEN status = 'failed' THEN 1 END) as failed_jobs,
AVG(processing_time) as avg_processing_time
FROM db_job_statistics
WHERE created_at BETWEEN ? AND ?";
$result = $this->db->doQuery($query, [
$dateRange['start'],
$dateRange['end']
]);
return $this->db->doFetch($result) ?: [];
}
/**
* Get growth statistics
* @param array $dateRange Date range
* @return array Growth statistics
*/
private function getGrowthStatistics($dateRange)
{
// Calculate growth rates
$currentPeriod = $this->getUserStatistics($dateRange);
// Get previous period for comparison
$previousStart = date('Y-m-d', strtotime($dateRange['start'] . ' -30 days'));
$previousEnd = date('Y-m-d', strtotime($dateRange['end'] . ' -30 days'));
$previousPeriod = $this->getUserStatistics(['start' => $previousStart, 'end' => $previousEnd]);
$userGrowth = $this->calculateGrowthRate(
$previousPeriod['new_users'] ?? 0,
$currentPeriod['new_users'] ?? 0
);
return [
'user_growth_rate' => $userGrowth,
'content_growth_rate' => 0, // Calculate similarly
'engagement_growth_rate' => 0 // Calculate similarly
];
}
/**
* Get date range from filters
* @param array $filters Filters
* @return array Date range
*/
private function getDateRange($filters)
{
$end = $filters['end_date'] ?? date('Y-m-d');
$start = $filters['start_date'] ?? date('Y-m-d', strtotime('-30 days'));
return [
'start' => $start,
'end' => $end
];
}
/**
* Check if user can view video analytics
* @param string $videoKey Video key
* @param int $userId User ID
* @return bool True if allowed
*/
private function canViewVideoAnalytics($videoKey, $userId)
{
// Check if user owns the video
$query = "SELECT usr_id FROM db_videofiles WHERE file_key = ?";
$result = $this->db->doQuery($query, [$videoKey]);
$video = $this->db->doFetch($result);
if ($video && $video['usr_id'] == $userId) {
return true;
}
// Check if user has admin permissions
return $this->rbac->hasPermission($userId, 'admin.analytics.view');
}
/**
* Calculate growth rate
* @param float $previous Previous value
* @param float $current Current value
* @return float Growth rate percentage
*/
private function calculateGrowthRate($previous, $current)
{
if ($previous == 0) {
return $current > 0 ? 100 : 0;
}
return round((($current - $previous) / $previous) * 100, 2);
}
/**
* Get country from IP address
* @param string $ip IP address
* @return string Country code
*/
private function getCountryFromIP($ip)
{
// Implement IP geolocation (use service like MaxMind GeoIP)
return 'US'; // Placeholder
}
/**
* Get device type from user agent
* @param string $userAgent User agent string
* @return string Device type
*/
private function getDeviceType($userAgent)
{
if (preg_match('/Mobile|Android|iPhone|iPad/', $userAgent)) {
return 'mobile';
} elseif (preg_match('/Tablet/', $userAgent)) {
return 'tablet';
} else {
return 'desktop';
}
}
/**
* Get active users count
* @return int Active users
*/
private function getActiveUsers()
{
$query = "SELECT COUNT(DISTINCT user_id) as count
FROM db_video_analytics
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 5 MINUTE)";
$result = $this->db->doQuery($query);
$row = $this->db->doFetch($result);
return (int)($row['count'] ?? 0);
}
/**
* Get live stream count
* @return int Live stream count
*/
private function getLiveStreamCount()
{
$query = "SELECT COUNT(*) as count FROM db_live_streams WHERE status = 'live'";
$result = $this->db->doQuery($query);
$row = $this->db->doFetch($result);
return (int)($row['count'] ?? 0);
}
/**
* Get current viewers
* @return int Current viewers
*/
private function getCurrentViewers()
{
$query = "SELECT SUM(viewer_count) as count FROM db_live_streams WHERE status = 'live'";
$result = $this->db->doQuery($query);
$row = $this->db->doFetch($result);
return (int)($row['count'] ?? 0);
}
/**
* Get recent uploads count
* @return int Recent uploads
*/
private function getRecentUploads()
{
$query = "SELECT COUNT(*) as count
FROM db_videofiles
WHERE upload_date >= DATE_SUB(NOW(), INTERVAL 1 HOUR)";
$result = $this->db->doQuery($query);
$row = $this->db->doFetch($result);
return (int)($row['count'] ?? 0);
}
/**
* Get server load
* @return array Server load metrics
*/
private function getServerLoad()
{
return [
'cpu_usage' => sys_getloadavg()[0] ?? 0,
'memory_usage' => memory_get_usage(true),
'disk_usage' => disk_free_space('.') ? (disk_total_space('.') - disk_free_space('.')) / disk_total_space('.') * 100 : 0
];
}
/**
* Get bandwidth usage
* @return array Bandwidth metrics
*/
private function getBandwidthUsage()
{
// This would typically come from server monitoring tools
return [
'incoming' => 0,
'outgoing' => 0,
'total' => 0
];
}
}