本文目录导读:

我来介绍几种在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 流程中集成版本徽章更新,这样既自动化又准确可靠。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播