- 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
749 lines
26 KiB
PHP
749 lines
26 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');
|
|
|
|
/**
|
|
* Social Features and User Interactions System
|
|
*/
|
|
class VSocial
|
|
{
|
|
private $logger;
|
|
private $db;
|
|
private static $instance = null;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->logger = VLogger::getInstance();
|
|
$this->db = VDatabase::getInstance();
|
|
}
|
|
|
|
public static function getInstance()
|
|
{
|
|
if (self::$instance === null) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Handle like/dislike action on content
|
|
* @param string $contentType Content type (video, comment, etc.)
|
|
* @param string $contentId Content ID
|
|
* @param string $userId User ID
|
|
* @param string $action Action (like, dislike, remove)
|
|
* @return array Result
|
|
*/
|
|
public function handleVote($contentType, $contentId, $userId, $action)
|
|
{
|
|
try {
|
|
if (!$userId) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'User must be logged in to vote'
|
|
];
|
|
}
|
|
|
|
// Validate content exists
|
|
if (!$this->validateContent($contentType, $contentId)) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Content not found'
|
|
];
|
|
}
|
|
|
|
// Check existing vote
|
|
$existingVote = $this->getExistingVote($contentType, $contentId, $userId);
|
|
|
|
// Handle vote logic
|
|
$result = $this->processVote($contentType, $contentId, $userId, $action, $existingVote);
|
|
|
|
// Update content vote counts
|
|
$this->updateVoteCounts($contentType, $contentId);
|
|
|
|
// Log the action
|
|
$this->logVoteAction($contentType, $contentId, $userId, $action, $result);
|
|
|
|
return [
|
|
'success' => true,
|
|
'action' => $result['action'],
|
|
'vote_counts' => $this->getVoteCounts($contentType, $contentId),
|
|
'user_vote' => $result['user_vote']
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
$this->logger->error('Vote handling failed', [
|
|
'content_type' => $contentType,
|
|
'content_id' => $contentId,
|
|
'user_id' => $userId,
|
|
'action' => $action,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Failed to process vote'
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add comment to content
|
|
* @param string $contentType Content type
|
|
* @param string $contentId Content ID
|
|
* @param string $userId User ID
|
|
* @param string $comment Comment text
|
|
* @param string $parentId Parent comment ID (for replies)
|
|
* @return array Result
|
|
*/
|
|
public function addComment($contentType, $contentId, $userId, $comment, $parentId = null)
|
|
{
|
|
try {
|
|
if (!$userId) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'User must be logged in to comment'
|
|
];
|
|
}
|
|
|
|
// Validate and sanitize comment
|
|
$comment = trim($comment);
|
|
if (empty($comment)) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Comment cannot be empty'
|
|
];
|
|
}
|
|
|
|
if (strlen($comment) > 2000) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Comment too long (max 2000 characters)'
|
|
];
|
|
}
|
|
|
|
// Validate content exists
|
|
if (!$this->validateContent($contentType, $contentId)) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Content not found'
|
|
];
|
|
}
|
|
|
|
// Check rate limiting
|
|
if (!$this->checkCommentRateLimit($userId)) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Too many comments. Please wait before commenting again.'
|
|
];
|
|
}
|
|
|
|
// Validate parent comment if replying
|
|
if ($parentId && !$this->validateParentComment($parentId, $contentType, $contentId)) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Parent comment not found'
|
|
];
|
|
}
|
|
|
|
// Filter comment content
|
|
$filteredComment = $this->filterCommentContent($comment);
|
|
|
|
// Create comment
|
|
$commentData = [
|
|
'content_type' => $contentType,
|
|
'content_id' => $contentId,
|
|
'user_id' => $userId,
|
|
'parent_id' => $parentId,
|
|
'comment_text' => $filteredComment,
|
|
'comment_status' => 'approved', // Could be 'pending' for moderation
|
|
'created_at' => date('Y-m-d H:i:s'),
|
|
'updated_at' => date('Y-m-d H:i:s'),
|
|
'likes_count' => 0,
|
|
'dislikes_count' => 0,
|
|
'replies_count' => 0
|
|
];
|
|
|
|
$commentId = $this->db->doInsert('db_comments', $commentData);
|
|
|
|
if (!$commentId) {
|
|
throw new Exception('Failed to create comment');
|
|
}
|
|
|
|
// Update parent comment reply count
|
|
if ($parentId) {
|
|
$this->db->doQuery(
|
|
"UPDATE db_comments SET replies_count = replies_count + 1 WHERE id = ?",
|
|
[$parentId]
|
|
);
|
|
}
|
|
|
|
// Update content comment count
|
|
$this->updateCommentCount($contentType, $contentId);
|
|
|
|
// Get comment with user info
|
|
$commentWithUser = $this->getCommentWithUser($commentId);
|
|
|
|
// Send notifications
|
|
$this->sendCommentNotifications($contentType, $contentId, $userId, $parentId);
|
|
|
|
$this->logger->info('Comment added successfully', [
|
|
'comment_id' => $commentId,
|
|
'content_type' => $contentType,
|
|
'content_id' => $contentId,
|
|
'user_id' => $userId
|
|
]);
|
|
|
|
return [
|
|
'success' => true,
|
|
'comment_id' => $commentId,
|
|
'comment' => $commentWithUser
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
$this->logger->error('Comment creation failed', [
|
|
'content_type' => $contentType,
|
|
'content_id' => $contentId,
|
|
'user_id' => $userId,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Failed to add comment'
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get comments for content
|
|
* @param string $contentType Content type
|
|
* @param string $contentId Content ID
|
|
* @param int $page Page number
|
|
* @param int $limit Comments per page
|
|
* @param string $sort Sort order (newest, oldest, popular)
|
|
* @return array Comments data
|
|
*/
|
|
public function getComments($contentType, $contentId, $page = 1, $limit = 20, $sort = 'newest')
|
|
{
|
|
try {
|
|
$offset = ($page - 1) * $limit;
|
|
|
|
// Build sort clause
|
|
$sortClause = $this->buildCommentSortClause($sort);
|
|
|
|
// Get top-level comments
|
|
$query = "SELECT c.*, u.usr_user, u.usr_avatar, u.usr_verified
|
|
FROM db_comments c
|
|
JOIN db_accountuser u ON c.user_id = u.usr_id
|
|
WHERE c.content_type = ? AND c.content_id = ?
|
|
AND c.parent_id IS NULL AND c.comment_status = 'approved'
|
|
ORDER BY {$sortClause}
|
|
LIMIT ? OFFSET ?";
|
|
|
|
$result = $this->db->doQuery($query, [$contentType, $contentId, $limit, $offset]);
|
|
|
|
$comments = [];
|
|
while ($row = $this->db->doFetch($result)) {
|
|
$comment = $this->formatComment($row);
|
|
|
|
// Get replies if any
|
|
if ($row['replies_count'] > 0) {
|
|
$comment['replies'] = $this->getCommentReplies($row['id'], 3); // Get first 3 replies
|
|
$comment['has_more_replies'] = $row['replies_count'] > 3;
|
|
}
|
|
|
|
$comments[] = $comment;
|
|
}
|
|
|
|
// Get total count
|
|
$countQuery = "SELECT COUNT(*) as total FROM db_comments
|
|
WHERE content_type = ? AND content_id = ?
|
|
AND parent_id IS NULL AND comment_status = 'approved'";
|
|
$countResult = $this->db->doQuery($countQuery, [$contentType, $contentId]);
|
|
$totalCount = $this->db->doFetch($countResult)['total'];
|
|
|
|
return [
|
|
'success' => true,
|
|
'comments' => $comments,
|
|
'pagination' => [
|
|
'current_page' => $page,
|
|
'per_page' => $limit,
|
|
'total' => $totalCount,
|
|
'total_pages' => ceil($totalCount / $limit),
|
|
'has_more' => $page < ceil($totalCount / $limit)
|
|
]
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
$this->logger->error('Failed to get comments', [
|
|
'content_type' => $contentType,
|
|
'content_id' => $contentId,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Failed to load comments'
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get comment replies
|
|
* @param string $parentId Parent comment ID
|
|
* @param int $limit Number of replies to get
|
|
* @return array Replies
|
|
*/
|
|
public function getCommentReplies($parentId, $limit = 10)
|
|
{
|
|
try {
|
|
$query = "SELECT c.*, u.usr_user, u.usr_avatar, u.usr_verified
|
|
FROM db_comments c
|
|
JOIN db_accountuser u ON c.user_id = u.usr_id
|
|
WHERE c.parent_id = ? AND c.comment_status = 'approved'
|
|
ORDER BY c.created_at ASC
|
|
LIMIT ?";
|
|
|
|
$result = $this->db->doQuery($query, [$parentId, $limit]);
|
|
|
|
$replies = [];
|
|
while ($row = $this->db->doFetch($result)) {
|
|
$replies[] = $this->formatComment($row);
|
|
}
|
|
|
|
return $replies;
|
|
|
|
} catch (Exception $e) {
|
|
$this->logger->error('Failed to get comment replies', [
|
|
'parent_id' => $parentId,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete comment
|
|
* @param string $commentId Comment ID
|
|
* @param string $userId User ID
|
|
* @return array Result
|
|
*/
|
|
public function deleteComment($commentId, $userId)
|
|
{
|
|
try {
|
|
// Get comment details
|
|
$comment = $this->getComment($commentId);
|
|
|
|
if (!$comment) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Comment not found'
|
|
];
|
|
}
|
|
|
|
// Check permissions (owner or admin)
|
|
if ($comment['user_id'] != $userId && !$this->isAdmin($userId)) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Permission denied'
|
|
];
|
|
}
|
|
|
|
// Soft delete comment
|
|
$this->db->doUpdate('db_comments', 'id', [
|
|
'comment_status' => 'deleted',
|
|
'updated_at' => date('Y-m-d H:i:s')
|
|
], $commentId);
|
|
|
|
// Update parent reply count if this is a reply
|
|
if ($comment['parent_id']) {
|
|
$this->db->doQuery(
|
|
"UPDATE db_comments SET replies_count = replies_count - 1 WHERE id = ?",
|
|
[$comment['parent_id']]
|
|
);
|
|
}
|
|
|
|
// Update content comment count
|
|
$this->updateCommentCount($comment['content_type'], $comment['content_id']);
|
|
|
|
$this->logger->info('Comment deleted', [
|
|
'comment_id' => $commentId,
|
|
'user_id' => $userId
|
|
]);
|
|
|
|
return [
|
|
'success' => true,
|
|
'message' => 'Comment deleted successfully'
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
$this->logger->error('Comment deletion failed', [
|
|
'comment_id' => $commentId,
|
|
'user_id' => $userId,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Failed to delete comment'
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate social sharing URLs
|
|
* @param string $contentType Content type
|
|
* @param string $contentId Content ID
|
|
* @return array Sharing URLs
|
|
*/
|
|
public function generateSharingUrls($contentType, $contentId)
|
|
{
|
|
try {
|
|
// Get content details
|
|
$content = $this->getContentDetails($contentType, $contentId);
|
|
|
|
if (!$content) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Content not found'
|
|
];
|
|
}
|
|
|
|
$baseUrl = $this->getBaseUrl();
|
|
$contentUrl = $baseUrl . $this->getContentUrl($contentType, $contentId);
|
|
$title = urlencode($content['title']);
|
|
$description = urlencode(substr($content['description'], 0, 200));
|
|
|
|
$sharingUrls = [
|
|
'facebook' => "https://www.facebook.com/sharer/sharer.php?u=" . urlencode($contentUrl),
|
|
'twitter' => "https://twitter.com/intent/tweet?url=" . urlencode($contentUrl) . "&text=" . $title,
|
|
'linkedin' => "https://www.linkedin.com/sharing/share-offsite/?url=" . urlencode($contentUrl),
|
|
'reddit' => "https://reddit.com/submit?url=" . urlencode($contentUrl) . "&title=" . $title,
|
|
'whatsapp' => "https://wa.me/?text=" . $title . "%20" . urlencode($contentUrl),
|
|
'telegram' => "https://t.me/share/url?url=" . urlencode($contentUrl) . "&text=" . $title,
|
|
'email' => "mailto:?subject=" . $title . "&body=" . $description . "%0A%0A" . urlencode($contentUrl),
|
|
'copy_link' => $contentUrl
|
|
];
|
|
|
|
return [
|
|
'success' => true,
|
|
'sharing_urls' => $sharingUrls,
|
|
'content_url' => $contentUrl,
|
|
'title' => $content['title']
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
$this->logger->error('Failed to generate sharing URLs', [
|
|
'content_type' => $contentType,
|
|
'content_id' => $contentId,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Failed to generate sharing URLs'
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Track social sharing action
|
|
* @param string $contentType Content type
|
|
* @param string $contentId Content ID
|
|
* @param string $platform Sharing platform
|
|
* @param string $userId User ID (optional)
|
|
*/
|
|
public function trackShare($contentType, $contentId, $platform, $userId = null)
|
|
{
|
|
try {
|
|
$shareData = [
|
|
'content_type' => $contentType,
|
|
'content_id' => $contentId,
|
|
'platform' => $platform,
|
|
'user_id' => $userId,
|
|
'ip_address' => $this->getRealIpAddress(),
|
|
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
|
|
'created_at' => date('Y-m-d H:i:s')
|
|
];
|
|
|
|
$this->db->doInsert('db_social_shares', $shareData);
|
|
|
|
// Update content share count
|
|
$this->updateShareCount($contentType, $contentId);
|
|
|
|
$this->logger->info('Social share tracked', [
|
|
'content_type' => $contentType,
|
|
'content_id' => $contentId,
|
|
'platform' => $platform,
|
|
'user_id' => $userId
|
|
]);
|
|
|
|
} catch (Exception $e) {
|
|
$this->logger->error('Failed to track share', [
|
|
'content_type' => $contentType,
|
|
'content_id' => $contentId,
|
|
'platform' => $platform,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get social statistics for content
|
|
* @param string $contentType Content type
|
|
* @param string $contentId Content ID
|
|
* @return array Social stats
|
|
*/
|
|
public function getSocialStats($contentType, $contentId)
|
|
{
|
|
try {
|
|
// Get vote counts
|
|
$voteCounts = $this->getVoteCounts($contentType, $contentId);
|
|
|
|
// Get comment count
|
|
$commentCount = $this->getCommentCount($contentType, $contentId);
|
|
|
|
// Get share count
|
|
$shareCount = $this->getShareCount($contentType, $contentId);
|
|
|
|
return [
|
|
'success' => true,
|
|
'stats' => [
|
|
'likes' => $voteCounts['likes'],
|
|
'dislikes' => $voteCounts['dislikes'],
|
|
'comments' => $commentCount,
|
|
'shares' => $shareCount,
|
|
'engagement_score' => $this->calculateEngagementScore($voteCounts, $commentCount, $shareCount)
|
|
]
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
$this->logger->error('Failed to get social stats', [
|
|
'content_type' => $contentType,
|
|
'content_id' => $contentId,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Failed to get social statistics'
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Private helper methods
|
|
*/
|
|
|
|
private function validateContent($contentType, $contentId)
|
|
{
|
|
$table = $this->getContentTable($contentType);
|
|
$idField = $this->getContentIdField($contentType);
|
|
|
|
$query = "SELECT 1 FROM {$table} WHERE {$idField} = ? AND file_active = 1 LIMIT 1";
|
|
$result = $this->db->doQuery($query, [$contentId]);
|
|
|
|
return $this->db->doFetch($result) !== false;
|
|
}
|
|
|
|
private function getExistingVote($contentType, $contentId, $userId)
|
|
{
|
|
$query = "SELECT vote_type FROM db_votes
|
|
WHERE content_type = ? AND content_id = ? AND user_id = ?";
|
|
$result = $this->db->doQuery($query, [$contentType, $contentId, $userId]);
|
|
|
|
$vote = $this->db->doFetch($result);
|
|
return $vote ? $vote['vote_type'] : null;
|
|
}
|
|
|
|
private function processVote($contentType, $contentId, $userId, $action, $existingVote)
|
|
{
|
|
if ($action === 'remove' || $action === $existingVote) {
|
|
// Remove existing vote
|
|
$this->db->doQuery(
|
|
"DELETE FROM db_votes WHERE content_type = ? AND content_id = ? AND user_id = ?",
|
|
[$contentType, $contentId, $userId]
|
|
);
|
|
|
|
return [
|
|
'action' => 'removed',
|
|
'user_vote' => null
|
|
];
|
|
} else {
|
|
// Add or update vote
|
|
$voteData = [
|
|
'content_type' => $contentType,
|
|
'content_id' => $contentId,
|
|
'user_id' => $userId,
|
|
'vote_type' => $action,
|
|
'created_at' => date('Y-m-d H:i:s')
|
|
];
|
|
|
|
if ($existingVote) {
|
|
// Update existing vote
|
|
$this->db->doQuery(
|
|
"UPDATE db_votes SET vote_type = ?, created_at = ?
|
|
WHERE content_type = ? AND content_id = ? AND user_id = ?",
|
|
[$action, date('Y-m-d H:i:s'), $contentType, $contentId, $userId]
|
|
);
|
|
} else {
|
|
// Insert new vote
|
|
$this->db->doInsert('db_votes', $voteData);
|
|
}
|
|
|
|
return [
|
|
'action' => $existingVote ? 'updated' : 'added',
|
|
'user_vote' => $action
|
|
];
|
|
}
|
|
}
|
|
|
|
private function updateVoteCounts($contentType, $contentId)
|
|
{
|
|
$table = $this->getContentTable($contentType);
|
|
$idField = $this->getContentIdField($contentType);
|
|
|
|
// Get current vote counts
|
|
$query = "SELECT
|
|
SUM(CASE WHEN vote_type = 'like' THEN 1 ELSE 0 END) as likes,
|
|
SUM(CASE WHEN vote_type = 'dislike' THEN 1 ELSE 0 END) as dislikes
|
|
FROM db_votes
|
|
WHERE content_type = ? AND content_id = ?";
|
|
|
|
$result = $this->db->doQuery($query, [$contentType, $contentId]);
|
|
$counts = $this->db->doFetch($result);
|
|
|
|
// Update content table
|
|
$updateQuery = "UPDATE {$table} SET
|
|
file_likes = ?, file_dislikes = ?
|
|
WHERE {$idField} = ?";
|
|
|
|
$this->db->doQuery($updateQuery, [
|
|
$counts['likes'] ?? 0,
|
|
$counts['dislikes'] ?? 0,
|
|
$contentId
|
|
]);
|
|
}
|
|
|
|
private function getVoteCounts($contentType, $contentId)
|
|
{
|
|
$query = "SELECT
|
|
SUM(CASE WHEN vote_type = 'like' THEN 1 ELSE 0 END) as likes,
|
|
SUM(CASE WHEN vote_type = 'dislike' THEN 1 ELSE 0 END) as dislikes
|
|
FROM db_votes
|
|
WHERE content_type = ? AND content_id = ?";
|
|
|
|
$result = $this->db->doQuery($query, [$contentType, $contentId]);
|
|
$counts = $this->db->doFetch($result);
|
|
|
|
return [
|
|
'likes' => (int)($counts['likes'] ?? 0),
|
|
'dislikes' => (int)($counts['dislikes'] ?? 0)
|
|
];
|
|
}
|
|
|
|
private function checkCommentRateLimit($userId)
|
|
{
|
|
// Check if user has posted more than 10 comments in the last hour
|
|
$query = "SELECT COUNT(*) as count FROM db_comments
|
|
WHERE user_id = ? AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)";
|
|
$result = $this->db->doQuery($query, [$userId]);
|
|
$count = $this->db->doFetch($result)['count'];
|
|
|
|
return $count < 10;
|
|
}
|
|
|
|
private function filterCommentContent($comment)
|
|
{
|
|
// Basic content filtering
|
|
$comment = strip_tags($comment);
|
|
$comment = htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');
|
|
|
|
// Remove excessive whitespace
|
|
$comment = preg_replace('/\s+/', ' ', $comment);
|
|
|
|
return trim($comment);
|
|
}
|
|
|
|
private function formatComment($row)
|
|
{
|
|
return [
|
|
'id' => $row['id'],
|
|
'content_type' => $row['content_type'],
|
|
'content_id' => $row['content_id'],
|
|
'parent_id' => $row['parent_id'],
|
|
'comment_text' => $row['comment_text'],
|
|
'created_at' => $row['created_at'],
|
|
'likes_count' => (int)$row['likes_count'],
|
|
'dislikes_count' => (int)$row['dislikes_count'],
|
|
'replies_count' => (int)$row['replies_count'],
|
|
'user' => [
|
|
'id' => $row['user_id'],
|
|
'username' => $row['usr_user'],
|
|
'avatar' => $row['usr_avatar'],
|
|
'verified' => (bool)$row['usr_verified']
|
|
],
|
|
'replies' => []
|
|
];
|
|
}
|
|
|
|
private function getContentTable($contentType)
|
|
{
|
|
$tables = [
|
|
'video' => 'db_videofiles',
|
|
'image' => 'db_imagefiles',
|
|
'audio' => 'db_audiofiles',
|
|
'document' => 'db_documentfiles'
|
|
];
|
|
|
|
return $tables[$contentType] ?? 'db_videofiles';
|
|
}
|
|
|
|
private function getContentIdField($contentType)
|
|
{
|
|
return 'file_key';
|
|
}
|
|
|
|
private function getBaseUrl()
|
|
{
|
|
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
|
|
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
|
|
return $protocol . '://' . $host;
|
|
}
|
|
|
|
private function getRealIpAddress()
|
|
{
|
|
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
|
return $_SERVER['HTTP_CLIENT_IP'];
|
|
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
|
return $_SERVER['HTTP_X_FORWARDED_FOR'];
|
|
} else {
|
|
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
|
|
}
|
|
}
|
|
|
|
private function calculateEngagementScore($voteCounts, $commentCount, $shareCount)
|
|
{
|
|
// Simple engagement score calculation
|
|
$likes = $voteCounts['likes'];
|
|
$dislikes = $voteCounts['dislikes'];
|
|
|
|
return ($likes * 1) + ($commentCount * 2) + ($shareCount * 3) - ($dislikes * 0.5);
|
|
}
|
|
|
|
// Additional helper methods would be implemented here...
|
|
} |