本文目录导读:

我来帮你创建一个PHP项目来统计禁区内射门次数对比,这个功能通常用于足球数据分析。
数据库设计
-- 球队表
CREATE TABLE teams (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
short_name VARCHAR(50)
);
-- 比赛表
CREATE TABLE matches (
id INT PRIMARY KEY AUTO_INCREMENT,
home_team_id INT,
away_team_id INT,
match_date DATE,
competition VARCHAR(100),
FOREIGN KEY (home_team_id) REFERENCES teams(id),
FOREIGN KEY (away_team_id) REFERENCES teams(id)
);
-- 射门记录表
CREATE TABLE shots (
id INT PRIMARY KEY AUTO_INCREMENT,
match_id INT,
team_id INT,
player_id INT,
shot_time INT, -- 比赛时间(分钟)
is_penalty_area BOOLEAN, -- 是否禁区内
is_goal BOOLEAN, -- 是否进球
shot_type VARCHAR(50), -- 射门方式:右脚、左脚、头球等
x_coordinate DECIMAL(4,2), -- x坐标(用于技术分析)
y_coordinate DECIMAL(4,2), -- y坐标
FOREIGN KEY (match_id) REFERENCES matches(id),
FOREIGN KEY (team_id) REFERENCES teams(id)
);
PHP配置和数据库连接
// config.php - 数据库配置文件
<?php
define('DB_HOST', 'localhost');
define('DB_NAME', 'football_stats');
define('DB_USER', 'root');
define('DB_PASS', 'your_password');
function getConnection() {
try {
$dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=utf8mb4';
$pdo = new PDO($dsn, DB_USER, DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
return $pdo;
} catch (PDOException $e) {
die('数据库连接失败: ' . $e->getMessage());
}
}
?>
射门统计类
// ShotStatistics.php - 射门统计类
<?php
class ShotStatistics {
private $db;
public function __construct() {
$this->db = getConnection();
}
// 获取比赛双方禁区内射门统计
public function getPenaltyAreaShotsByMatch($matchId) {
$sql = "SELECT
t.id as team_id,
t.name as team_name,
COUNT(CASE WHEN s.is_penalty_area = 1 THEN 1 END) as area_shots,
COUNT(CASE WHEN s.is_penalty_area = 1 AND s.is_goal = 1 THEN 1 END) as area_goals,
COUNT(CASE WHEN s.is_penalty_area = 0 THEN 1 END) as outside_shots,
COUNT(CASE WHEN s.is_penalty_area = 0 AND s.is_goal = 1 THEN 1 END) as outside_goals,
COUNT(*) as total_shots
FROM matches m
INNER JOIN teams t ON t.id IN (m.home_team_id, m.away_team_id)
LEFT JOIN shots s ON s.match_id = m.id AND s.team_id = t.id
WHERE m.id = ?
GROUP BY t.id, t.name";
$stmt = $this->db->prepare($sql);
$stmt->execute([$matchId]);
return $stmt->fetchAll();
}
// 获取多场比赛的禁区内射门统计
public function getSeasonPenaltyAreaStats($teamId = null, $startDate = null, $endDate = null) {
$params = [];
$sql = "SELECT
t.id as team_id,
t.name as team_name,
COUNT(s.id) as total_shots,
SUM(s.is_penalty_area) as area_shots,
SUM(CASE WHEN s.is_penalty_area = 1 AND s.is_goal = 1 THEN 1 ELSE 0 END) as area_goals,
ROUND(SUM(s.is_penalty_area) / COUNT(s.id) * 100, 2) as area_shot_percentage,
ROUND(SUM(CASE WHEN s.is_penalty_area = 1 AND s.is_goal = 1 THEN 1 ELSE 0 END) /
NULLIF(SUM(s.is_penalty_area), 0) * 100, 2) as area_conversion_rate
FROM teams t
LEFT JOIN shots s ON s.team_id = t.id
LEFT JOIN matches m ON m.id = s.match_id
WHERE 1=1";
if ($teamId) {
$sql .= " AND t.id = ?";
$params[] = $teamId;
}
if ($startDate) {
$sql .= " AND m.match_date >= ?";
$params[] = $startDate;
}
if ($endDate) {
$sql .= " AND m.match_date <= ?";
$params[] = $endDate;
}
$sql .= " GROUP BY t.id, t.name ORDER BY area_shots DESC";
$stmt = $this->db->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
}
// 获取球员禁区内射门统计
public function getPlayerAreaShots($playerId) {
$sql = "SELECT
p.name as player_name,
COUNT(*) as total_shots,
SUM(CASE WHEN s.is_penalty_area = 1 THEN 1 ELSE 0 END) as area_shots,
SUM(CASE WHEN s.is_penalty_area = 1 AND s.is_goal = 1 THEN 1 ELSE 0 END) as area_goals
FROM players p
LEFT JOIN shots s ON s.player_id = p.id
WHERE p.id = ?
GROUP BY p.name";
$stmt = $this->db->prepare($sql);
$stmt->execute([$playerId]);
return $stmt->fetch();
}
// 获取每场比赛禁区内射门时间分布
public function getShotTimeDistribution($matchId) {
$sql = "SELECT
CASE
WHEN shot_time BETWEEN 0 AND 15 THEN '0-15分钟'
WHEN shot_time BETWEEN 16 AND 30 THEN '16-30分钟'
WHEN shot_time BETWEEN 31 AND 45 THEN '31-45分钟'
WHEN shot_time BETWEEN 46 AND 60 THEN '46-60分钟'
WHEN shot_time BETWEEN 61 AND 75 THEN '61-75分钟'
ELSE '76-90分钟'
END as time_period,
COUNT(CASE WHEN is_penalty_area = 1 THEN 1 END) as area_shots,
COUNT(CASE WHEN is_penalty_area = 0 THEN 1 END) as outside_shots,
COUNT(*) as total_shots
FROM shots
WHERE match_id = ?
GROUP BY time_period
ORDER BY shot_time";
$stmt = $this->db->prepare($sql);
$stmt->execute([$matchId]);
return $stmt->fetchAll();
}
}
?>
页面展示
// compare_shots.php - 禁区内射门对比页面
<?php
require_once 'config.php';
require_once 'ShotStatistics.php';
$stats = new ShotStatistics();
// 获取比赛列表(用于选择)
$db = getConnection();
$matches = $db->query("SELECT m.id,
home.name as home_team,
away.name as away_team,
m.match_date
FROM matches m
JOIN teams home ON home.id = m.home_team_id
JOIN teams away ON away.id = m.away_team_id
ORDER BY m.match_date DESC LIMIT 10")->fetchAll();
$selectedMatch = isset($_GET['match_id']) ? $_GET['match_id'] : (isset($matches[0]) ? $matches[0]['id'] : null);
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">禁区内射门统计对比</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
.container { max-width: 1200px; margin-top: 30px; }
.card { margin-bottom: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.stat-card { border-radius: 8px; }
.area-highlight { background-color: #28a745; color: white; }
.progress { height: 30px; }
</style>
</head>
<body>
<div class="container">
<h1 class="mb-4">⚽ 禁区内射门统计对比</h1>
<!-- 比赛选择 -->
<div class="card p-3 mb-4">
<form method="GET" class="row g-3">
<div class="col-md-6">
<label for="match_id" class="form-label">选择比赛</label>
<select name="match_id" id="match_id" class="form-select" onchange="this.form.submit()">
<?php foreach ($matches as $match): ?>
<option value="<?= $match['id'] ?>" <?= $selectedMatch == $match['id'] ? 'selected' : '' ?>>
<?= $match['home_team'] ?> vs <?= $match['away_team'] ?> (<?= date('Y-m-d', strtotime($match['match_date'])) ?>)
</option>
<?php endforeach; ?>
</select>
</div>
</form>
</div>
<?php if ($selectedMatch): ?>
<?php $matchStats = $stats->getPenaltyAreaShotsByMatch($selectedMatch); ?>
<!-- 射门对比图表 -->
<div class="card p-4">
<h4 class="mb-3">禁区内射门对比</h4>
<div class="row">
<div class="col-md-8">
<canvas id="shotChart"></canvas>
</div>
<div class="col-md-4">
<?php foreach ($matchStats as $team): ?>
<div class="mb-3 p-3 border rounded">
<h5><?= $team['team_name'] ?></h5>
<div class="mb-2">禁区内射门: <strong><?= $team['area_shots'] ?? 0 ?></strong> 次</div>
<div class="mb-2">禁区外射门: <strong><?= $team['outside_shots'] ?? 0 ?></strong> 次</div>
<div class="mb-2">禁区内进球: <strong class="text-success"><?= $team['area_goals'] ?? 0 ?></strong> 个</div>
<div class="progress mb-2">
<div class="progress-bar bg-success" style="width: <?= $team['total_shots'] > 0 ? ($team['area_shots'] / $team['total_shots'] * 100) : 0 ?>%">
<?= $team['total_shots'] > 0 ? round($team['area_shots'] / $team['total_shots'] * 100) : 0 ?>%
</div>
</div>
<small class="text-muted">禁区内射门占比</small>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<!-- 射门时间分布 -->
<div class="card p-4 mt-4">
<h4>射门时间分布</h4>
<canvas id="timeChart" width="400" height="200"></canvas>
</div>
<!-- 统计数据表 -->
<div class="card p-4 mt-4">
<h4>详细统计</h4>
<table class="table table-striped">
<thead>
<tr>
<th>球队</th>
<th>总射门</th>
<th>禁区内射门</th>
<th>禁区外射门</th>
<th>禁区内进球</th>
<th>禁区射门转化率</th>
</tr>
</thead>
<tbody>
<?php foreach ($matchStats as $team): ?>
<tr>
<td><?= $team['team_name'] ?></td>
<td><?= $team['total_shots'] ?></td>
<td class="text-success"><?= $team['area_shots'] ?? 0 ?></td>
<td><?= $team['outside_shots'] ?? 0 ?></td>
<td><?= $team['area_goals'] ?? 0 ?></td>
<td>
<?= $team['area_shots'] > 0 ? number_format($team['area_goals'] / $team['area_shots'] * 100, 2) : 0 ?>%
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<script>
// 射门对比图表
const matchStats = <?= json_encode($matchStats) ?>;
const ctx1 = document.getElementById('shotChart').getContext('2d');
new Chart(ctx1, {
type: 'bar',
data: {
labels: matchStats.map(t => t.team_name),
datasets: [
{
label: '禁区内射门',
data: matchStats.map(t => t.area_shots || 0),
backgroundColor: 'rgba(40, 167, 69, 0.7)',
borderColor: 'rgba(40, 167, 69, 1)',
borderWidth: 1
},
{
label: '禁区外射门',
data: matchStats.map(t => t.outside_shots || 0),
backgroundColor: 'rgba(255, 193, 7, 0.7)',
borderColor: 'rgba(255, 193, 7, 1)',
borderWidth: 1
}
]
},
options: {
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: '射门次数'
}
}
},
plugins: {
title: {
display: true,
text: '球队射门分布对比'
}
}
}
});
</script>
<?php endif; ?>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
赛季统计数据
// season_stats.php - 赛季禁区内射门统计
<?php
require_once 'config.php';
require_once 'ShotStatistics.php';
$stats = new ShotStatistics();
$seasonStats = $stats->getSeasonPenaltyAreaStats(null, '2024-01-01', '2024-12-31');
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">赛季禁区内射门统计</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-4">
<h2>2024赛季禁区内射门统计</h2>
<div class="card p-4">
<table class="table table-hover">
<thead>
<tr>
<th>排名</th>
<th>球队</th>
<th>总射门</th>
<th>禁区内射门</th>
<th>禁区内进球</th>
<th>禁区射门占比</th>
<th>禁区进球转化率</th>
</tr>
</thead>
<tbody>
<?php $rank = 1; ?>
<?php foreach ($seasonStats as $stat): ?>
<tr>
<td><?= $rank++ ?></td>
<td><?= $stat['team_name'] ?></td>
<td><?= $stat['total_shots'] ?></td>
<td><?= $stat['area_shots'] ?></td>
<td><?= $stat['area_goals'] ?></td>
<td><?= $stat['area_shot_percentage'] ?>%</td>
<td><?= $stat['area_conversion_rate'] ?>%</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</body>
</html>
数据导入示例
// import_shots_data.php - 数据导入示例
<?php
require_once 'ShotStatistics.php';
function importShotData($matchId, $shots) {
$db = getConnection();
$insertSql = "INSERT INTO shots (match_id, team_id, player_id, shot_time, is_penalty_area, is_goal, shot_type, x_coordinate, y_coordinate)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
$stmt = $db->prepare($insertSql);
foreach ($shots as $shot) {
$stmt->execute([
$matchId,
$shot['team_id'],
$shot['player_id'],
$shot['shot_time'],
$shot['is_penalty_area'],
$shot['is_goal'],
$shot['shot_type'],
$shot['x_coordinate'],
$shot['y_coordinate']
]);
}
echo "成功导入 " . count($shots) . " 条射门数据";
}
?>
使用说明
- 配置数据库: 执行提供的SQL语句创建表结构
- 设置连接: 修改
config.php中的数据库连接信息 - 导入数据: 通过管理后台录入或批量导入射门数据
- 访问页面:
- 运行
compare_shots.php查看单场比赛对比 - 运行
season_stats.php查看赛季统计数据
- 运行
这个系统的特点:
- 支持多场比赛、多球队对比
- 提供可视化图表展示
- 可扩展性强,可以添加更多统计维度(如射门方向、射门方式等)
- 支持时间段筛选和历史数据对比
你可以根据实际需求调整统计维度和展示方式,需要我添加其他功能吗?