execute("SELECT file_type FROM db_videofiles WHERE file_key = '$file_key_safe'"); $file_type = 'NULL'; if ($typeResult && $typeResult->RecordCount() > 0) { $row = $typeResult->FetchRow(); $file_type = "'" . VDatabase::escape($row['file_type']) . "'"; } $sql = "INSERT INTO db_analytics_events (usr_id, session_id, event_type, file_key, file_type, event_data, timestamp_sec, ip_address, user_agent, referrer, created_at) VALUES ($usr_id, '$session_safe', '$event_type_safe', '$file_key_safe', $file_type, '$data_json', $timestamp, '$ip', '$ua', '$referrer', NOW())"; self::$db->execute($sql); // Update retention data for video events if ($event_type == 'play' || $event_type == 'pause') { self::updateRetention($file_key, $timestamp); } } /** * Update retention data */ private static function updateRetention($file_key, $timestamp_sec) { if (!$timestamp_sec) return; $file_key_safe = VDatabase::escape($file_key); $timestamp = (int)$timestamp_sec; $sql = "INSERT INTO db_analytics_retention (file_key, timestamp_sec, viewers, updated_at) VALUES ('$file_key_safe', $timestamp, 1, NOW()) ON DUPLICATE KEY UPDATE viewers = viewers + 1, updated_at = NOW()"; self::$db->execute($sql); } /** * Get retention graph data * @param string $file_key File key * @return array Retention data by second */ public static function getRetentionGraph($file_key) { self::init(); $file_key_safe = VDatabase::escape($file_key); $sql = "SELECT timestamp_sec, viewers FROM db_analytics_retention WHERE file_key = '$file_key_safe' ORDER BY timestamp_sec ASC"; $result = self::$db->execute($sql); $data = []; if ($result) { while ($row = $result->FetchRow()) { $data[] = [ 'time' => (int)$row['timestamp_sec'], 'viewers' => (int)$row['viewers'] ]; } } return $data; } /** * Get traffic sources * @param string $file_key File key * @param string $date_from Start date * @param string $date_to End date * @return array Traffic sources */ public static function getTrafficSources($file_key, $date_from, $date_to) { self::init(); $file_key_safe = VDatabase::escape($file_key); $from_safe = VDatabase::escape($date_from); $to_safe = VDatabase::escape($date_to); // Analyze referrers from events $sql = "SELECT CASE WHEN referrer = '' THEN 'direct' WHEN referrer LIKE '%google%' OR referrer LIKE '%bing%' THEN 'search' WHEN referrer LIKE '%facebook%' OR referrer LIKE '%twitter%' OR referrer LIKE '%instagram%' THEN 'social' WHEN referrer LIKE '%{$_SERVER['HTTP_HOST']}%' THEN 'internal' ELSE 'external' END as source_type, COUNT(*) as visits FROM db_analytics_events WHERE file_key = '$file_key_safe' AND event_type = 'view' AND DATE(created_at) BETWEEN '$from_safe' AND '$to_safe' GROUP BY source_type"; $result = self::$db->execute($sql); $sources = []; if ($result) { while ($row = $result->FetchRow()) { $sources[] = [ 'source' => $row['source_type'], 'visits' => (int)$row['visits'] ]; } } return $sources; } /** * Get analytics summary * @param string $file_key File key * @param string $date_from Start date * @param string $date_to End date * @return array Summary data */ public static function getSummary($file_key, $date_from, $date_to) { self::init(); $file_key_safe = VDatabase::escape($file_key); $from_safe = VDatabase::escape($date_from); $to_safe = VDatabase::escape($date_to); $sql = "SELECT COUNT(DISTINCT session_id) as unique_viewers, COUNT(*) as total_views, SUM(CASE WHEN event_type = 'like' THEN 1 ELSE 0 END) as likes, SUM(CASE WHEN event_type = 'comment' THEN 1 ELSE 0 END) as comments, SUM(CASE WHEN event_type = 'share' THEN 1 ELSE 0 END) as shares FROM db_analytics_events WHERE file_key = '$file_key_safe' AND DATE(created_at) BETWEEN '$from_safe' AND '$to_safe'"; $result = self::$db->execute($sql); if ($result && $result->RecordCount() > 0) { return $result->FetchRow(); } return []; } /** * Track heatmap click * @param string $file_key File key * @param float $x X coordinate (0-1) * @param float $y Y coordinate (0-1) * @param string $type Type (click or hover) */ public static function trackHeatmap($file_key, $x, $y, $type = 'click') { self::init(); $file_key_safe = VDatabase::escape($file_key); $x = (float)$x; $y = (float)$y; $date = date('Y-m-d'); $field = $type == 'hover' ? 'hovers' : 'clicks'; $sql = "INSERT INTO db_analytics_heatmaps (file_key, x_coord, y_coord, $field, date) VALUES ('$file_key_safe', $x, $y, 1, '$date') ON DUPLICATE KEY UPDATE $field = $field + 1"; self::$db->execute($sql); } /** * Get heatmap data * @param string $file_key File key * @param string $date Date * @return array Heatmap coordinates */ public static function getHeatmap($file_key, $date) { self::init(); $file_key_safe = VDatabase::escape($file_key); $date_safe = VDatabase::escape($date); $sql = "SELECT x_coord, y_coord, clicks, hovers FROM db_analytics_heatmaps WHERE file_key = '$file_key_safe' AND date = '$date_safe'"; $result = self::$db->execute($sql); $heatmap = []; if ($result) { while ($row = $result->FetchRow()) { $heatmap[] = [ 'x' => (float)$row['x_coord'], 'y' => (float)$row['y_coord'], 'clicks' => (int)$row['clicks'], 'hovers' => (int)$row['hovers'], 'intensity' => (int)$row['clicks'] + ((int)$row['hovers'] / 10) ]; } } return $heatmap; } }