本文目录导读:

我将为您设计一个完整的PHP邮件营销系统架构,这个系统将包含订阅管理、模板制作、发送队列、统计分析等核心功能。
系统架构设计
数据库设计
-- 订阅者表
CREATE TABLE subscribers (
id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(100),
status ENUM('active', 'unsubscribed', 'bounced', 'spam') DEFAULT 'active',
source VARCHAR(50),
ip_address VARCHAR(45),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
unsubscribed_at TIMESTAMP NULL,
INDEX idx_email (email),
INDEX idx_status (status),
INDEX idx_created (created_at)
);
-- 订阅分组表
CREATE TABLE subscriber_groups (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 订阅者-分组关联表
CREATE TABLE subscriber_group_members (
subscriber_id INT,
group_id INT,
subscribed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (subscriber_id, group_id),
FOREIGN KEY (subscriber_id) REFERENCES subscribers(id) ON DELETE CASCADE,
FOREIGN KEY (group_id) REFERENCES subscriber_groups(id) ON DELETE CASCADE
);
-- 邮件模板表
CREATE TABLE email_templates (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(200) NOT NULL,
subject VARCHAR(500) NOT NULL,
content TEXT NOT NULL,
content_type ENUM('text', 'html') DEFAULT 'html',
variables JSON,
created_by INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 发送任务表
CREATE TABLE campaigns (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(200) NOT NULL,
template_id INT,
group_ids JSON,
subject VARCHAR(500),
sender_name VARCHAR(100),
sender_email VARCHAR(255),
reply_to VARCHAR(255),
status ENUM('draft', 'scheduled', 'sending', 'completed', 'paused', 'cancelled') DEFAULT 'draft',
scheduled_at TIMESTAMP NULL,
started_at TIMESTAMP NULL,
completed_at TIMESTAMP NULL,
total_recipients INT DEFAULT 0,
sent_count INT DEFAULT 0,
opened_count INT DEFAULT 0,
clicked_count INT DEFAULT 0,
bounced_count INT DEFAULT 0,
unsubscribed_count INT DEFAULT 0,
created_by INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (template_id) REFERENCES email_templates(id)
);
-- 邮件发送队列表
CREATE TABLE email_queue (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
campaign_id INT,
subscriber_id INT,
email VARCHAR(255) NOT NULL,
subject VARCHAR(500),
content TEXT,
status ENUM('pending', 'sending', 'sent', 'failed', 'opened', 'clicked', 'bounced', 'unsubscribed') DEFAULT 'pending',
attempts INT DEFAULT 0,
max_attempts INT DEFAULT 3,
error_message TEXT,
sent_at TIMESTAMP NULL,
opened_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_campaign_status (campaign_id, status),
INDEX idx_subscriber (subscriber_id),
INDEX idx_created (created_at),
FOREIGN KEY (campaign_id) REFERENCES campaigns(id),
FOREIGN KEY (subscriber_id) REFERENCES subscribers(id)
);
-- 邮件点击追踪表
CREATE TABLE email_tracking (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
queue_id BIGINT,
subscriber_id INT,
click_url VARCHAR(2000),
ip_address VARCHAR(45),
user_agent TEXT,
clicked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (queue_id) REFERENCES email_queue(id),
FOREIGN KEY (subscriber_id) REFERENCES subscribers(id)
);
核心类设计
<?php
// MailMarketingSystem.php
class MailMarketingSystem {
private $db;
private $config;
private $mailer;
public function __construct(PDO $db, array $config) {
$this->db = $db;
$this->config = $config;
$this->mailer = $this->initMailer();
}
// 订阅管理
public function subscribe(string $email, string $name = '', array $groups = [], string $source = 'webform'): bool {
try {
// 验证邮箱
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new Exception('Invalid email address');
}
// 检查是否已存在
$existing = $this->getSubscriberByEmail($email);
if ($existing) {
// 更新订阅状态(如果之前退订了)
if ($existing['status'] === 'unsubscribed') {
$this->reactivateSubscriber($existing['id']);
}
return true;
}
// 开启事务
$this->db->beginTransaction();
// 插入订阅者
$stmt = $this->db->prepare("
INSERT INTO subscribers (email, name, status, source, ip_address)
VALUES (:email, :name, 'active', :source, :ip)
");
$stmt->execute([
'email' => $email,
'name' => $name,
'source' => $source,
'ip' => $_SERVER['REMOTE_ADDR'] ?? ''
]);
$subscriberId = $this->db->lastInsertId();
// 添加到分组
if (!empty($groups)) {
$this->addSubscriberToGroups($subscriberId, $groups);
}
$this->db->commit();
// 发送确认邮件(可选)
$this->sendConfirmationEmail($email, $name);
return true;
} catch (Exception $e) {
$this->db->rollBack();
$this->logError('Subscribe failed: ' . $e->getMessage());
return false;
}
}
// 取消订阅
public function unsubscribe(string $email): bool {
try {
$stmt = $this->db->prepare("
UPDATE subscribers
SET status = 'unsubscribed', unsubscribed_at = NOW()
WHERE email = :email
");
return $stmt->execute(['email' => $email]);
} catch (Exception $e) {
$this->logError('Unsubscribe failed: ' . $e->getMessage());
return false;
}
}
// 创建邮件模板
public function createTemplate(string $name, string $subject, string $content, array $variables = []): int {
// 预处理模板变量
$processedContent = $this->processTemplateVariables($content, $variables);
$stmt = $this->db->prepare("
INSERT INTO email_templates (name, subject, content, variables)
VALUES (:name, :subject, :content, :variables)
");
$stmt->execute([
'name' => $name,
'subject' => $subject,
'content' => $processedContent,
'variables' => json_encode($variables)
]);
return $this->db->lastInsertId();
}
// 创建发送任务
public function createCampaign(array $data): int {
$stmt = $this->db->prepare("
INSERT INTO campaigns (
name, template_id, group_ids, subject,
sender_name, sender_email, reply_to,
scheduled_at, status, created_by
) VALUES (
:name, :template_id, :group_ids, :subject,
:sender_name, :sender_email, :reply_to,
:scheduled_at, 'draft', :created_by
)
");
$stmt->execute([
'name' => $data['name'],
'template_id' => $data['template_id'],
'group_ids' => json_encode($data['group_ids']),
'subject' => $data['subject'] ?? '',
'sender_name' => $data['sender_name'] ?? $this->config['default_sender_name'],
'sender_email' => $data['sender_email'] ?? $this->config['default_sender_email'],
'reply_to' => $data['reply_to'] ?? '',
'scheduled_at' => $data['scheduled_at'] ?? null,
'created_by' => $data['created_by']
]);
return $this->db->lastInsertId();
}
// 准备邮件队列
public function prepareCampaignQueue(int $campaignId): int {
$campaign = $this->getCampaign($campaignId);
if (!$campaign || $campaign['status'] !== 'draft') {
return 0;
}
// 获取目标订阅者
$subscribers = $this->getCampaignSubscribers($campaign);
// 获取模板内容
$template = $this->getTemplate($campaign['template_id']);
$count = 0;
$this->db->beginTransaction();
try {
$stmt = $this->db->prepare("
INSERT INTO email_queue (campaign_id, subscriber_id, email, subject, content, status)
VALUES (:campaign_id, :subscriber_id, :email, :subject, :content, 'pending')
");
foreach ($subscribers as $subscriber) {
// 个性化处理
$personalized = $this->personalizeEmail($template, $subscriber);
$stmt->execute([
'campaign_id' => $campaignId,
'subscriber_id' => $subscriber['id'],
'email' => $subscriber['email'],
'subject' => $personalized['subject'],
'content' => $personalized['content']
]);
$count++;
}
// 更新任务统计
$this->db->prepare("
UPDATE campaigns
SET total_recipients = :count, status = 'scheduled'
WHERE id = :id
")->execute(['count' => $count, 'id' => $campaignId]);
$this->db->commit();
} catch (Exception $e) {
$this->db->rollBack();
$this->logError('Prepare queue failed: ' . $e->getMessage());
return 0;
}
return $count;
}
// 发送邮件(批量处理)
public function sendCampaignEmails(int $campaignId, int $limit = 50): array {
$result = ['sent' => 0, 'failed' => 0];
// 获取待发送的邮件
$stmt = $this->db->prepare("
SELECT * FROM email_queue
WHERE campaign_id = :campaign_id AND status = 'pending'
LIMIT :limit
");
$stmt->execute(['campaign_id' => $campaignId, 'limit' => $limit]);
$emails = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($emails as $email) {
try {
// 更新状态为发送中
$this->updateQueueStatus($email['id'], 'sending');
// 添加追踪像素
$trackingPixel = $this->generateTrackingPixel($email['id']);
$email['content'] = str_replace('</body>', $trackingPixel . '</body>', $email['content']);
// 替换链接为追踪链接
$email['content'] = $this->replaceLinksWithTracking($email['content'], $email['id']);
// 发送邮件
$sent = $this->mailer->send([
'to' => $email['email'],
'subject' => $email['subject'],
'body' => $email['content'],
'tracking_id' => $email['id']
]);
if ($sent) {
$this->updateQueueStatus($email['id'], 'sent', ['sent_at' => date('Y-m-d H:i:s')]);
$this->incrementCampaignCounter($campaignId, 'sent_count');
$result['sent']++;
} else {
throw new Exception('Failed to send email');
}
} catch (Exception $e) {
$this->handleSendFailure($email, $e->getMessage());
$result['failed']++;
}
// 速率限制
usleep(200000); // 200ms 延迟
}
// 检查是否完成
$this->checkCampaignCompletion($campaignId);
return $result;
}
// 处理退信
public function handleBounce(string $email, string $bounceType = 'hard'): void {
$status = $bounceType === 'hard' ? 'bounced' : 'soft_bounce';
$stmt = $this->db->prepare("
UPDATE subscribers SET status = :status WHERE email = :email
");
$stmt->execute(['status' => $status, 'email' => $email]);
// 更新发送队列
$this->db->prepare("
UPDATE email_queue
SET status = 'bounced', error_message = :type
WHERE email = :email AND status IN ('sent', 'pending')
")->execute(['type' => $bounceType, 'email' => $email]);
}
// 处理打开追踪
public function trackOpen(string $trackingId): void {
$stmt = $this->db->prepare("
UPDATE email_queue
SET status = 'opened', opened_at = NOW()
WHERE id = :id AND status = 'sent'
");
$stmt->execute(['id' => base64_decode($trackingId)]);
}
// 处理点击追踪
public function trackClick(string $trackingId, string $url): void {
$queueId = base64_decode($trackingId);
$stmt = $this->db->prepare("
INSERT INTO email_tracking (queue_id, subscriber_id, click_url, ip_address, user_agent)
SELECT :queue_id, subscriber_id, :url, :ip, :ua
FROM email_queue WHERE id = :queue_id2
");
$stmt->execute([
'queue_id' => $queueId,
'url' => $url,
'ip' => $_SERVER['REMOTE_ADDR'],
'ua' => $_SERVER['HTTP_USER_AGENT'],
'queue_id2' => $queueId
]);
// 更新状态
$this->db->prepare("
UPDATE email_queue SET status = 'clicked' WHERE id = :id AND status = 'opened'
")->execute(['id' => $queueId]);
}
// 生成统计报告
public function getCampaignStats(int $campaignId): array {
$campaign = $this->getCampaign($campaignId);
$stats = [
'total' => $campaign['total_recipients'],
'sent' => $campaign['sent_count'],
'opened' => $campaign['opened_count'],
'clicked' => $campaign['clicked_count'],
'bounced' => $campaign['bounced_count'],
'unsubscribed' => $campaign['unsubscribed_count'],
];
// 计算比率
$stats['open_rate'] = $stats['sent'] > 0 ? round($stats['opened'] / $stats['sent'] * 100, 2) : 0;
$stats['click_rate'] = $stats['opened'] > 0 ? round($stats['clicked'] / $stats['opened'] * 100, 2) : 0;
$stats['bounce_rate'] = $stats['total'] > 0 ? round($stats['bounced'] / $stats['total'] * 100, 2) : 0;
return $stats;
}
// 私有辅助方法
private function initMailer() {
// 初始化邮件发送器(支持SMTP、Sendmail等)
return new Mailer($this->config['mail']);
}
private function personalizeEmail(array $template, array $subscriber): array {
$variables = json_decode($template['variables'], true) ?? [];
$replacements = [
'{{name}}' => $subscriber['name'],
'{{email}}' => $subscriber['email'],
'{{unsubscribe_url}}' => $this->generateUnsubscribeUrl($subscriber['email']),
];
// 自定义变量替换
foreach ($variables as $var => $field) {
$replacements["{{{$var}}}"] = $subscriber[$field] ?? '';
}
$subject = strtr($template['subject'], $replacements);
$content = strtr($template['content'], $replacements);
return ['subject' => $subject, 'content' => $content];
}
private function generateTrackingPixel(int $queueId): string {
$encoded = base64_encode($queueId);
$url = $this->config['tracking_url'] . "/open/{$encoded}.gif";
return "<img src=\"{$url}\" width=\"1\" height=\"1\" alt=\"\" />";
}
private function replaceLinksWithTracking(string $content, int $queueId): string {
$encoded = base64_encode($queueId);
$trackingUrl = $this->config['tracking_url'] . "/click/{$encoded}?url=";
return preg_replace_callback(
'/href=["\'](https?:\/\/[^"\']+)["\']/i',
function($matches) use ($trackingUrl) {
return 'href="' . $trackingUrl . urlencode($matches[1]) . '"';
},
$content
);
}
private function handleSendFailure(array $email, string $error): void {
$attempts = $email['attempts'] + 1;
if ($attempts >= $email['max_attempts']) {
$status = 'failed';
} else {
$status = 'pending';
}
$this->db->prepare("
UPDATE email_queue
SET status = :status, attempts = :attempts, error_message = :error
WHERE id = :id
")->execute([
'status' => $status,
'attempts' => $attempts,
'error' => $error,
'id' => $email['id']
]);
}
private function checkCampaignCompletion(int $campaignId): void {
$stmt = $this->db->prepare("
SELECT COUNT(*) as pending
FROM email_queue
WHERE campaign_id = :id AND status IN ('pending', 'sending')
");
$stmt->execute(['id' => $campaignId]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result['pending'] == 0) {
$this->db->prepare("
UPDATE campaigns
SET status = 'completed', completed_at = NOW()
WHERE id = :id
")->execute(['id' => $campaignId]);
}
}
// ... 其他辅助方法
}
命令行发送处理器
<?php
// cron/send_emails.php
require_once __DIR__ . '/../bootstrap.php';
$system = new MailMarketingSystem($db, $config);
// 获取所有待发送的任务
$stmt = $db->prepare("
SELECT id FROM campaigns
WHERE status IN ('scheduled', 'sending')
AND (scheduled_at IS NULL OR scheduled_at <= NOW())
ORDER BY created_at ASC
");
$stmt->execute();
$campaigns = $stmt->fetchAll(PDO::FETCH_COLUMN);
foreach ($campaigns as $campaignId) {
// 更新状态为发送中
$db->prepare("UPDATE campaigns SET status = 'sending', started_at = NOW() WHERE id = :id")
->execute(['id' => $campaignId]);
// 分批发送
$batchSize = 50;
$totalSent = 0;
while (true) {
$result = $system->sendCampaignEmails($campaignId, $batchSize);
$totalSent += $result['sent'];
if ($result['sent'] == 0) {
break;
}
// 检查是否应该暂停(根据内存使用或时间限制)
if (memory_get_usage(true) > 100 * 1024 * 1024) { // 100MB
break;
}
}
echo "Campaign #{$campaignId}: Sent {$totalSent} emails\n";
}
订阅管理表单示例
<!-- subscribe_form.php -->
<!DOCTYPE html>
<html>
<head>订阅我们的邮件</title>
<style>
.subscribe-form { max-width: 400px; margin: 50px auto; padding: 20px; }
.form-group { margin-bottom: 15px; }
.form-group label { display: block; margin-bottom: 5px; }
.form-group input[type="email"],
.form-group input[type="text"] { width: 100%; padding: 8px; box-sizing: border-box; }
.submit-btn { background: #007bff; color: white; padding: 10px 20px; border: none; cursor: pointer; }
.message { padding: 10px; margin-bottom: 15px; border-radius: 4px; }
.success { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
</style>
</head>
<body>
<div class="subscribe-form">
<?php if (isset($_GET['status'])): ?>
<?php if ($_GET['status'] === 'success'): ?>
<div class="message success">订阅成功!请查收确认邮件。</div>
<?php elseif ($_GET['status'] === 'exists'): ?>
<div class="message success">您已经订阅过了。</div>
<?php else: ?>
<div class="message error">订阅失败,请稍后重试。</div>
<?php endif; ?>
<?php endif; ?>
<h2>订阅我们的邮件通讯</h2>
<form method="POST" action="process_subscribe.php">
<div class="form-group">
<label for="name">姓名</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">邮箱地址</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label>感兴趣的主题</label><br>
<label><input type="checkbox" name="interests[]" value="news"> 新闻资讯</label><br>
<label><input type="checkbox" name="interests[]" value="promotions"> 优惠活动</label><br>
<label><input type="checkbox" name="interests[]" value="updates"> 产品更新</label>
</div>
<button type="submit" class="submit-btn">立即订阅</button>
</form>
<p style="margin-top: 20px; font-size: 12px; color: #666;">
我们尊重您的隐私,绝不会分享您的信息,您可以随时取消订阅。
</p>
</div>
</body>
</html>
退订处理页面
<?php
// unsubscribe.php
require_once 'config/database.php';
require_once 'classes/MailMarketingSystem.php';
$system = new MailMarketingSystem($db, $config);
$email = $_GET['email'] ?? '';
$token = $_GET['token'] ?? '';
// 验证退订令牌
if (empty($email) || empty($token) || !$system->verifyUnsubscribeToken($email, $token)) {
die('Invalid unsubscribe link');
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($_POST['confirm'] === 'yes') {
$system->unsubscribe($email);
$message = '您已成功取消订阅。';
$success = true;
} else {
header('Location: /');
exit;
}
}
?>
<!DOCTYPE html>
<html>
<head>取消订阅</title>
</head>
<body>
<div style="max-width: 500px; margin: 50px auto; text-align: center; padding: 20px;">
<?php if (isset($message)): ?>
<h2><?= htmlspecialchars($message) ?></h2>
<p>如果您改变主意,随时可以重新订阅。</p>
<?php else: ?>
<h2>确定要取消订阅吗?</h2>
<p>您将停止接收来自我们所有的邮件通讯。</p>
<form method="POST">
<button type="submit" name="confirm" value="yes" style="background: #dc3545; color: white; padding: 10px 20px; border: none; cursor: pointer;">
确认取消订阅
</button>
<button type="submit" name="confirm" value="no" style="background: #6c757d; color: white; padding: 10px 20px; border: none; cursor: pointer; margin-left: 10px;">
保持订阅
</button>
</form>
<?php endif; ?>
</div>
</body>
</html>
API端点示例
<?php
// api/email_marketing.php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
require_once '../config/database.php';
require_once '../classes/MailMarketingSystem.php';
$system = new MailMarketingSystem($db, $config);
$method = $_SERVER['REQUEST_METHOD'];
$endpoint = $_GET['endpoint'] ?? '';
// API认证
function authenticate() {
$headers = getallheaders();
$token = $headers['Authorization'] ?? '';
// 验证API token
return $token === 'your-api-key';
}
if (!authenticate()) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
switch ($endpoint) {
case 'subscribe':
if ($method === 'POST') {
$data = json_decode(file_get_contents('php://input'), true);
$result = $system->subscribe(
$data['email'],
$data['name'] ?? '',
$data['groups'] ?? [],
'api'
);
echo json_encode(['success' => $result]);
}
break;
case 'unsubscribe':
if ($method === 'POST') {
$data = json_decode(file_get_contents('php://input'), true);
$result = $system->unsubscribe($data['email']);
echo json_encode(['success' => $result]);
}
break;
case 'subscribers':
if ($method === 'GET') {
// 获取订阅者列表
$page = $_GET['page'] ?? 1;
$limit = $_GET['limit'] ?? 20;
$subscribers = $system->getSubscribers($page, $limit);
echo json_encode($subscribers);
}
break;
case 'campaigns':
if ($method === 'GET') {
$campaigns = $system->getCampaigns();
echo json_encode($campaigns);
} elseif ($method === 'POST') {
$data = json_decode(file_get_contents('php://input'), true);
$id = $system->createCampaign($data);
echo json_encode(['id' => $id]);
}
break;
case 'stats':
if ($method === 'GET') {
$campaignId = $_GET['campaign_id'];
$stats = $system->getCampaignStats($campaignId);
echo json_encode($stats);
}
break;
default:
http_response_code(404);
echo json_encode(['error' => 'Endpoint not found']);
}
部署建议
系统配置示例
<?php
// config/email_marketing.php
return [
'db' => [
'host' => 'localhost',
'dbname' => 'email_marketing',
'username' => 'root',
'password' => '',
],
'mail' => [
'driver' => 'smtp',
'host' => 'smtp.gmail.com',
'port' => 587,
'username' => 'your-email@gmail.com',
'password' => 'your-password',
'encryption' => 'tls',
],
'default_sender_name' => 'Your Company',
'default_sender_email' => 'noreply@yourcompany.com',
'tracking_url' => 'https://yourdomain.com/track',
'unsubscribe_url' => 'https://yourdomain.com/unsubscribe',
'sending' => [
'batch_size' => 50,
'delay_between_emails' => 200000, // 微秒
'max_attempts' => 3,
],
'limits' => [
'daily_send_limit' => 10000,
'max_recipients_per_campaign' => 5000,
'rate_limit_per_hour' => 1000,
],
];
维护计划
每日任务
- 清理失败的邮件队列
- 更新退信列表
- 生成每日报告
每周任务
- 清理无效/重复订阅者
- 优化数据库索引
- 检查发送限制
每月任务
- 归档旧数据
- 更新邮件模板
- 审查发送策略
安全注意事项
- 邮件验证:使用双重确认(Double Opt-in)
- 速率限制:防止滥用和服务器过载
- 数据加密:敏感信息加密存储
- 退订机制:必须包含一键退订
- 认证授权:API使用token认证
- 日志记录:记录所有操作以便审计
- 防注入:所有用户输入需要验证和清理
这个系统设计提供了完整的邮件营销功能,可以根据实际需求进行调整和扩展,建议在生产环境前进行充分的测试,特别是大规模发送时的性能和稳定性测试。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播