本文目录导读:

我来为您提供一个PHP项目热门排行榜的完整实现方案,包含多种热门计算方式。
数据库设计
CREATE TABLE `hot_items` ( `id` int(11) NOT NULL AUTO_INCREMENT, varchar(255) NOT NULL COMMENT '标题', `type` varchar(50) NOT NULL COMMENT '类型:article/product/user等', `item_id` int(11) NOT NULL COMMENT '对应项目ID', `views` int(11) DEFAULT 0 COMMENT '浏览量', `likes` int(11) DEFAULT 0 COMMENT '点赞数', `comments` int(11) DEFAULT 0 COMMENT '评论数', `shares` int(11) DEFAULT 0 COMMENT '分享数', `collections` int(11) DEFAULT 0 COMMENT '收藏数', `hot_score` decimal(10,2) DEFAULT 0.00 COMMENT '热度分数', `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_hot_score` (`hot_score` DESC), KEY `idx_type` (`type`), KEY `idx_updated_at` (`updated_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 热度日志表 CREATE TABLE `hot_logs` ( `id` int(11) NOT NULL AUTO_INCREMENT, `item_id` int(11) NOT NULL, `action` varchar(20) NOT NULL COMMENT '操作类型', `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_item_id` (`item_id`), KEY `idx_created_at` (`created_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
核心热度计算类
<?php
// HotRank.php
class HotRank {
private $db;
private $cache;
// 权重配置
private $weights = [
'views' => 1,
'likes' => 3,
'comments' => 5,
'shares' => 8,
'collections' => 4
];
// 时间衰减参数(天)
private $timeDecayDays = 7;
public function __construct($db, $cache = null) {
$this->db = $db;
$this->cache = $cache;
}
/**
* 计算单个项目的热度分数
* @param array $item 项目数据
* @return float
*/
public function calculateScore($item) {
// 基础分数
$baseScore = 0;
foreach ($this->weights as $field => $weight) {
$baseScore += ($item[$field] ?? 0) * $weight;
}
// 时间衰减因子(使用指数衰减)
$hoursPassed = (time() - strtotime($item['created_at'])) / 3600;
$timeDecay = exp(-$hoursPassed / ($this->timeDecayDays * 24));
// 最终分数
return round($baseScore * $timeDecay, 2);
}
/**
* 批量更新热度分数
*/
public function updateAllScores() {
$sql = "UPDATE hot_items SET hot_score = ? WHERE id = ?";
$stmt = $this->db->prepare($sql);
// 获取所有项目
$items = $this->db->query("SELECT * FROM hot_items")->fetchAll();
foreach ($items as $item) {
$score = $this->calculateScore($item);
$stmt->execute([$score, $item['id']]);
}
}
/**
* 记录操作日志
*/
public function logAction($itemId, $action) {
$sql = "INSERT INTO hot_logs (item_id, action) VALUES (?, ?)";
$this->db->prepare($sql)->execute([$itemId, $action]);
}
/**
* 实时更新计数
*/
public function updateCount($itemId, $action, $increment = 1) {
// 允许的字段映射
$fieldMap = [
'view' => 'views',
'like' => 'likes',
'comment' => 'comments',
'share' => 'shares',
'collection' => 'collections'
];
if (!isset($fieldMap[$action])) {
return false;
}
$field = $fieldMap[$action];
// 更新计数
$sql = "UPDATE hot_items SET {$field} = {$field} + ? WHERE id = ?";
$this->db->prepare($sql)->execute([$increment, $itemId]);
// 记录日志
$this->logAction($itemId, $action);
// 清理缓存
$this->clearCache();
return true;
}
/**
* 获取热门排行榜
* @param string $type 类型
* @param int $limit 数量
* @param int $offset 偏移
* @return array
*/
public function getRanking($type = null, $limit = 10, $offset = 0) {
$cacheKey = "hot_ranking_{$type}_{$limit}_{$offset}";
// 尝试从缓存获取
if ($this->cache) {
$cached = $this->cache->get($cacheKey);
if ($cached !== false) {
return json_decode($cached, true);
}
}
// 构建查询
$where = $type ? "WHERE type = ?" : "";
$sql = "SELECT h.*,
CASE
WHEN h.type = 'article' THEN (SELECT title FROM articles WHERE id = h.item_id)
WHEN h.type = 'product' THEN (SELECT name FROM products WHERE id = h.item_id)
ELSE h.title
END as display_title
FROM hot_items h
{$where}
ORDER BY hot_score DESC
LIMIT ? OFFSET ?";
$stmt = $this->db->prepare($sql);
if ($type) {
$stmt->execute([$type, $limit, $offset]);
} else {
$stmt->execute([$limit, $offset]);
}
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 缓存结果(5分钟)
if ($this->cache) {
$this->cache->set($cacheKey, json_encode($result), 300);
}
return $result;
}
/**
* 获取热度趋势
*/
public function getTrendingItems($hours = 24, $limit = 10) {
$startTime = date('Y-m-d H:i:s', time() - $hours * 3600);
$sql = "SELECT item_id, action, COUNT(*) as count
FROM hot_logs
WHERE created_at >= ?
GROUP BY item_id, action
ORDER BY count DESC
LIMIT ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$startTime, $limit * 5]); // 获取更多数据用于计算
return $this->processTrendingData($stmt->fetchAll(PDO::FETCH_ASSOC), $limit);
}
/**
* 处理趋势数据
*/
private function processTrendingData($logs, $limit) {
$itemScores = [];
foreach ($logs as $log) {
$itemId = $log['item_id'];
$weight = $this->weights[$log['action']] ?? 1;
if (!isset($itemScores[$itemId])) {
$itemScores[$itemId] = 0;
}
$itemScores[$itemId] += $log['count'] * $weight;
}
// 排序并取前N个
arsort($itemScores);
$topIds = array_slice(array_keys($itemScores), 0, $limit);
// 获取完整信息
return $this->getItemsByIds($topIds);
}
/**
* 根据ID获取项目信息
*/
private function getItemsByIds($ids) {
if (empty($ids)) return [];
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$sql = "SELECT * FROM hot_items WHERE id IN ({$placeholders})";
$stmt = $this->db->prepare($sql);
$stmt->execute($ids);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 清除缓存
*/
private function clearCache() {
if ($this->cache) {
// 清除相关缓存
$this->cache->deleteByPrefix('hot_ranking_');
}
}
}
控制器实现
<?php
// HotRankController.php
class HotRankController {
private $hotRank;
public function __construct($hotRank) {
$this->hotRank = $hotRank;
}
/**
* 记录用户操作
*/
public function recordAction($itemId, $action) {
// 验证操作类型
$validActions = ['view', 'like', 'comment', 'share', 'collection'];
if (!in_array($action, $validActions)) {
http_response_code(400);
return json_encode(['error' => 'Invalid action']);
}
// 防止刷单(IP限制)
$ip = $_SERVER['REMOTE_ADDR'];
// 这里可以添加IP限制逻辑
$result = $this->hotRank->updateCount($itemId, $action);
return json_encode(['success' => $result]);
}
/**
* 获取排行榜
*/
public function getRanking() {
$type = $_GET['type'] ?? null;
$limit = min(intval($_GET['limit'] ?? 10), 100);
$offset = intval($_GET['offset'] ?? 0);
// 验证类型
$validTypes = ['article', 'product', 'user'];
if ($type && !in_array($type, $validTypes)) {
$type = null;
}
$ranking = $this->hotRank->getRanking($type, $limit, $offset);
return json_encode([
'code' => 0,
'data' => $ranking,
'total' => count($ranking)
]);
}
/**
* 获取趋势
*/
public function getTrending() {
$hours = min(intval($_GET['hours'] ?? 24), 168);
$limit = min(intval($_GET['limit'] ?? 10), 50);
$trending = $this->hotRank->getTrendingItems($hours, $limit);
return json_encode([
'code' => 0,
'data' => $trending
]);
}
/**
* 手动更新分数(通常由Cron执行)
*/
public function updateScores() {
// 验证执行权限
if (!isset($_GET['secret']) || $_GET['secret'] !== CRON_SECRET) {
http_response_code(403);
return json_encode(['error' => 'Unauthorized']);
}
$startTime = microtime(true);
$this->hotRank->updateAllScores();
$execTime = microtime(true) - $startTime;
return json_encode([
'success' => true,
'exec_time' => round($execTime, 4)
]);
}
}
路由配置
<?php
// routes.php
$router = new Router();
$controller = new HotRankController(new HotRank($db, $cache));
// 记录操作
$router->post('/api/hot/action', [$controller, 'recordAction']);
// 获取排行榜
$router->get('/api/hot/ranking', [$controller, 'getRanking']);
// 获取趋势
$router->get('/api/hot/trending', [$controller, 'getTrending']);
// 更新分数(Cron调用)
$router->get('/api/hot/update-scores', [$controller, 'updateScores']);
前端集成示例
// hot-ranking.js
class HotRanking {
constructor(options) {
this.apiUrl = options.apiUrl || '/api/hot';
this.container = options.container;
this.type = options.type || null;
this.limit = options.limit || 10;
this.interval = options.interval || 30000; // 30秒刷新
this.init();
}
init() {
this.fetchRanking();
// 定时刷新
setInterval(() => this.fetchRanking(), this.interval);
}
async fetchRanking() {
try {
const params = new URLSearchParams({
limit: this.limit
});
if (this.type) {
params.append('type', this.type);
}
const response = await fetch(`${this.apiUrl}/ranking?${params}`);
const data = await response.json();
if (data.code === 0) {
this.render(data.data);
}
} catch (error) {
console.error('Failed to fetch ranking:', error);
}
}
render(items) {
if (!this.container) return;
const html = items.map((item, index) => `
<div class="hot-item">
<span class="rank ${index < 3 ? 'top' : ''}">${index + 1}</span>
<div class="item-info">
<h3>${item.display_title || item.title}</h3>
<div class="stats">
<span>🔥 ${item.hot_score}</span>
<span>👁 ${item.views}</span>
<span>❤️ ${item.likes}</span>
</div>
</div>
</div>
`).join('');
this.container.innerHTML = html;
}
// 记录用户操作
static recordAction(itemId, action) {
fetch('/api/hot/action', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ item_id: itemId, action: action })
}).catch(error => console.error('Failed to record action:', error));
}
}
// 使用示例
document.addEventListener('DOMContentLoaded', () => {
const ranking = new HotRanking({
container: document.getElementById('hot-ranking'),
type: 'article',
limit: 20
});
// 记录点击
document.addEventListener('click', (e) => {
const item = e.target.closest('.hot-item');
if (item) {
HotRanking.recordAction(item.dataset.itemId, 'view');
}
});
});
定时任务配置
# crontab - 每30分钟更新一次热度分数 */30 * * * * php /path/to/cron/update_hot_scores.php # 或者使用更复杂的策略 # 0 */2 * * * php /path/to/cron/update_hot_scores.php
Cron脚本
<?php
// cron/update_hot_scores.php
require_once __DIR__ . '/../vendor/autoload.php';
// 初始化数据库连接
$db = new PDO('mysql:host=localhost;dbname=test', 'root', '');
// 创建热门排名实例
$hotRank = new HotRank($db);
// 更新所有分数
$startTime = microtime(true);
$hotRank->updateAllScores();
$execTime = microtime(true) - $startTime;
// 记录日志
file_put_contents(
__DIR__ . '/../logs/hot_update.log',
date('Y-m-d H:i:s') . " - Updated scores in {$execTime}s\n",
FILE_APPEND
);
echo "Scores updated in {$execTime}s\n";
高级功能扩展
1 加权时间衰减算法
// 更复杂的时间衰减算法
public function calculateAdvancedScore($item) {
$baseScore = 0;
// 基础分数计算
foreach ($this->weights as $field => $weight) {
$baseScore += $item[$field] * $weight;
}
// 使用对数衰减(更平稳)
$hoursPassed = (time() - strtotime($item['created_at'])) / 3600;
if ($hoursPassed > 0) {
$timeFactor = 1 / log10($hoursPassed + 10);
} else {
$timeFactor = 1;
}
// 新鲜度加成(最近24小时内的活动)
$recentActivity = $this->getRecentActivity($item['id'], 24);
$freshnessBonus = $recentActivity * 0.5;
return round(($baseScore * $timeFactor) + $freshnessBonus, 2);
}
/**
* 获取近期活动数
*/
private function getRecentActivity($itemId, $hours) {
$sql = "SELECT COUNT(*) FROM hot_logs
WHERE item_id = ? AND created_at >= DATE_SUB(NOW(), INTERVAL ? HOUR)";
$stmt = $this->db->prepare($sql);
$stmt->execute([$itemId, $hours]);
return $stmt->fetchColumn();
}
2 Redis缓存实现
// RedisCache.php
class RedisCache {
private $redis;
private $prefix = 'hot_rank:';
public function __construct($redis) {
$this->redis = $redis;
}
public function get($key) {
return $this->redis->get($this->prefix . $key);
}
public function set($key, $value, $ttl = 300) {
return $this->redis->setex($this->prefix . $key, $ttl, $value);
}
public function delete($key) {
return $this->redis->del($this->prefix . $key);
}
public function deleteByPrefix($prefix) {
$keys = $this->redis->keys($this->prefix . $prefix . '*');
if (!empty($keys)) {
return $this->redis->del($keys);
}
return 0;
}
}
防刷机制
// AntiFraud.php
class AntiFraud {
private $redis;
private $limits = [
'view' => ['count' => 100, 'time' => 3600], // 每小时100次浏览
'like' => ['count' => 10, 'time' => 3600], // 每小时10次点赞
'comment' => ['count' => 5, 'time' => 3600], // 每小时5次评论
];
public function checkFraud($userId, $action) {
if (!isset($this->limits[$action])) {
return true;
}
$limit = $this->limits[$action];
$key = "fraud:{$userId}:{$action}";
$count = $this->redis->incr($key);
// 第一次设置过期时间
if ($count === 1) {
$this->redis->expire($key, $limit['time']);
}
return $count <= $limit['count'];
}
public function isSuspicious($itemId, $action) {
// 检查短时间内的大量操作
$sql = "SELECT COUNT(*) FROM hot_logs
WHERE item_id = ? AND action = ?
AND created_at > DATE_SUB(NOW(), INTERVAL 1 MINUTE)";
// 如果1分钟内超过50次,标记为可疑
// 这里实现略
return false;
}
}
性能优化建议
-
数据库优化
- 创建复合索引:(type, hot_score)
- 使用分区表按月分表
- 定期清理过期日志
-
缓存策略
- 排行榜结果缓存5分钟
- 热门度分数缓存30分钟
- 使用Redis实现高性能缓存
-
异步处理
- 使用消息队列处理操作记录
- 异步更新热度分数
- 批量处理日志写入
-
配置调整
- 根据业务调整权重参数
- 动态调整时间衰减因子
- 区分不同类型内容的权重
这个完整的排行榜实现包含了数据库设计、核心算法、缓存机制、防刷策略等关键功能,可以根据实际需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播