本文目录导读:

我来介绍几种在PHP项目中自动化版本徽章的方法:
使用 Shields.io 动态徽章
从 Packagist 获取版本
// 如果你使用 Composer 发布包 // 直接在 README.md 中添加: [](https://packagist.org/packages/vendor/package) [](https://packagist.org/packages/vendor/package)
从 GitHub Releases 获取
[](https://github.com/username/repo/releases)
自定义 PHP 脚本生成徽章
基础版本徽章生成器
<?php
class BadgeGenerator
{
public static function generateSVGBadge($label, $value, $color = '#007ec6')
{
$labelWidth = strlen($label) * 7 + 20;
$valueWidth = strlen($value) * 7 + 20;
$totalWidth = $labelWidth + $valueWidth;
$svg = <<<SVG
<svg xmlns="http://www.w3.org/2000/svg" width="{$totalWidth}" height="20">
<linearGradient id="smooth" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="round">
<rect width="{$totalWidth}" height="20" rx="3" fill="#fff"/>
</mask>
<g mask="url(#round)">
<rect width="{$labelWidth}" height="20" fill="#555"/>
<rect x="{$labelWidth}" width="{$valueWidth}" height="20" fill="{$color}"/>
<rect width="{$totalWidth}" height="20" fill="url(#smooth)"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
<text x="{$labelWidth/2}" y="15" fill="#010101" fill-opacity=".3">{$label}</text>
<text x="{$labelWidth/2}" y="14">{$label}</text>
<text x="{$labelWidth + $valueWidth/2}" y="15" fill="#010101" fill-opacity=".3">{$value}</text>
<text x="{$labelWidth + $valueWidth/2}" y="14">{$value}</text>
</g>
</svg>
SVG;
header('Content-Type: image/svg+xml');
echo $svg;
}
// 从 composer.lock 获取版本
public static function getAppVersion($composerLockFile = 'composer.lock')
{
if (!file_exists($composerLockFile)) {
return 'dev';
}
$lockData = json_decode(file_get_contents($composerLockFile), true);
$rootPackage = $lockData['packages'][0] ?? null;
if ($rootPackage && isset($rootPackage['version'])) {
return ltrim($rootPackage['version'], 'v');
}
return 'unknown';
}
}
// 使用示例
if (isset($_GET['badge']) && $_GET['badge'] === 'version') {
$version = BadgeGenerator::getAppVersion();
BadgeGenerator::generateSVGBadge('Version', $version);
}
?>
使用 Git 钩子自动化更新
pre-commit 钩子
#!/bin/bash
# .git/hooks/pre-commit
# 获取当前版本
VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "0.0.0")
# 更新版本文件
cat > version.php << EOF
<?php
define('APP_VERSION', '$VERSION');
define('APP_VERSION_DATE', '$(date -u +%Y-%m-%dT%H:%M:%S)Z');
?>
EOF
git add version.php
CI/CD 集成方案
GitHub Actions 示例
# .github/workflows/version-badge.yml
name: Update Version Badge
on:
push:
tags:
- 'v*'
jobs:
update-badge:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Get version
id: get_version
run: echo "::set-output name=VERSION::${GITHUB_REF#refs/tags/v}"
- name: Update version file
run: |
echo "<?php define('APP_VERSION', '${{ steps.get_version.outputs.VERSION }}'); ?>" > version.php
echo "🗞️ 版本徽章已更新为 ${{ steps.get_version.outputs.VERSION }}"
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "🔖 Update version badge to ${{ steps.get_version.outputs.VERSION }}"
branch: main
实时版本检测系统
<?php
class VersionBadgeSystem
{
private $cacheFile = 'cache/version.json';
public function getBadgeData()
{
// 检查缓存
if (file_exists($this->cacheFile)) {
$cached = json_decode(file_get_contents($this->cacheFile), true);
if (time() - $cached['timestamp'] < 3600) { // 1小时缓存
return $cached;
}
}
// 获取最新版本信息
$data = [
'version' => $this->detectVersion(),
'date' => date('c'),
'commit' => $this->getLastCommit(),
'timestamp' => time()
];
// 保存缓存
file_put_contents(
$this->cacheFile,
json_encode($data, JSON_PRETTY_PRINT)
);
return $data;
}
private function detectVersion()
{
// 优先从 Git 获取
if (function_exists('exec')) {
$gitVersion = exec('git describe --tags --abbrev=0 2>/dev/null');
if ($gitVersion) {
return ltrim($gitVersion, 'v');
}
}
// 回退到 composer.json
if (file_exists('composer.json')) {
$composer = json_decode(file_get_contents('composer.json'), true);
if (isset($composer['version'])) {
return $composer['version'];
}
}
return 'dev-master';
}
private function getLastCommit()
{
if (function_exists('exec')) {
return exec('git log -1 --format="%h" 2>/dev/null');
}
return 'none';
}
public function renderBadge()
{
$badge = new BadgeGenerator();
$data = $this->getBadgeData();
return $badge->generateSVGBadge(
'Version',
$data['version'],
$this->getVersionColor($data['version'])
);
}
private function getVersionColor($version)
{
if (preg_match('/^\d+\.\d+\.\d+$/', $version)) {
return '#4c1'; // 稳定版 - 绿色
} elseif (preg_match('/^[0-9]+\.[0-9]+\.\d+-[a-z0-9]+$/i', $version)) {
return '#97ca00'; // 预发布 - 黄绿色
}
return '#fe7d37'; // 开发版本 - 橙色
}
}
// 使用
$badgeSystem = new VersionBadgeSystem();
$badgeSystem->renderBadge();
?>
集成到 README 自动更新脚本
<?php
// update_readme_badge.php
class ReadmeBadgeUpdater
{
public function update()
{
$version = $this->getCurrentVersion();
$readmeFile = 'README.md';
if (!file_exists($readmeFile)) {
die("README.md 不存在\n");
}
$content = file_get_contents($readmeFile);
// 替换版本徽章标记
$pattern = '/\[![Vv]ersion\].*?\)/';
$replacement = "[]";
$newContent = preg_replace($pattern, $replacement, $content);
if ($newContent !== $content) {
file_put_contents($readmeFile, $newContent);
echo "✅ README.md 版本徽章已更新到 v{$version}\n";
} else {
echo "ℹ️ 版本无变化,无需更新\n";
}
}
private function getCurrentVersion()
{
// 从 Git tag 获取
if (function_exists('exec')) {
$tag = exec('git describe --tags $(git rev-list --tags --max-count=1) 2>/dev/null');
if ($tag) {
return ltrim($tag, 'v');
}
}
// 从 composer.json 获取
$composer = json_decode(file_get_contents('composer.json'), true);
return $composer['version'] ?? '0.1.0';
}
}
// 执行更新
$updater = new ReadmeBadgeUpdater();
$updater->update();
?>
现代化解决方案
推荐组合方案:
- Shields.io + Packagist 最简单,自动维护
- GitHub Actions 自动化构建和版本徽章更新
- 自定义 SVG 生成器 需要完全自己控制时
- Badge 缓存系统 需要高并发时
最佳实践是在 CI/CD 流程中集成版本徽章更新,这样既自动化又准确可靠。