文章目录[隐藏]
WordPress柔性供应链软件开发中的持续集成与部署教程
引言:柔性供应链与WordPress开发的结合
在当今快速变化的商业环境中,柔性供应链系统已成为企业保持竞争力的关键。将这种灵活性融入WordPress开发中,可以创建出既能适应需求波动又能保持稳定性的供应链解决方案。然而,随着系统复杂性的增加,如何确保代码质量和部署效率成为开发团队面临的重要挑战。持续集成与部署(CI/CD)正是解决这一问题的有效方法。
本文将详细介绍在WordPress柔性供应链软件开发中实施CI/CD的完整流程,包括环境配置、自动化测试、部署策略等关键环节,并提供可直接使用的代码示例。
环境配置与基础架构
1.1 版本控制系统设置
首先,我们需要建立代码版本控制系统。Git是目前最流行的选择,配合GitHub、GitLab或Bitbucket等平台使用。
# 初始化Git仓库
git init
# 添加远程仓库
git remote add origin https://github.com/your-username/wordpress-supply-chain.git
# 创建基础分支结构
git checkout -b main
git checkout -b develop
git checkout -b feature/supply-chain-module
# 创建.gitignore文件,排除不需要版本控制的文件
echo "# WordPress核心文件(不应包含在仓库中)
wordpress/
wp-config.php
# 依赖文件
node_modules/
vendor/
# 环境配置文件
.env
.env.local
# 系统文件
.DS_Store
Thumbs.db
# IDE文件
.idea/
.vscode/
*.swp
# 日志文件
*.log" > .gitignore
1.2 Docker容器化配置
使用Docker可以确保开发、测试和生产环境的一致性。以下是Docker配置示例:
# Dockerfile - WordPress柔性供应链应用
FROM wordpress:php8.0-apache
# 设置工作目录
WORKDIR /var/www/html
# 安装系统依赖
RUN apt-get update && apt-get install -y
git
unzip
curl
libzip-dev
libpng-dev
libjpeg-dev
libfreetype6-dev
&& docker-php-ext-configure gd --with-freetype --with-jpeg
&& docker-php-ext-install -j$(nproc) gd zip pdo_mysql
# 安装Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# 复制自定义代码
COPY wp-content/plugins/supply-chain /var/www/html/wp-content/plugins/supply-chain
COPY wp-content/themes/supply-chain-theme /var/www/html/wp-content/themes/supply-chain-theme
# 设置权限
RUN chown -R www-data:www-data /var/www/html
&& chmod -R 755 /var/www/html/wp-content
# 暴露端口
EXPOSE 80
# 启动Apache
CMD ["apache2-foreground"]
# docker-compose.yml - 多容器环境配置
version: '3.8'
services:
db:
image: mysql:8.0
container_name: wp_supply_chain_db
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- db_data:/var/lib/mysql
networks:
- wordpress-network
wordpress:
build: .
container_name: wp_supply_chain
restart: always
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: ${DB_USER}
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
WORDPRESS_DB_NAME: ${DB_NAME}
volumes:
- wordpress_data:/var/www/html/wp-content
- ./custom-plugins:/var/www/html/wp-content/plugins/custom
depends_on:
- db
networks:
- wordpress-network
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: wp_supply_chain_pma
restart: always
ports:
- "8081:80"
environment:
PMA_HOST: db
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
networks:
- wordpress-network
networks:
wordpress-network:
driver: bridge
volumes:
db_data:
wordpress_data:
持续集成流水线配置
2.1 GitHub Actions工作流配置
GitHub Actions提供了强大的CI/CD功能。以下是一个完整的WordPress插件测试工作流:
# .github/workflows/ci-cd.yml
name: WordPress供应链插件CI/CD
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
# 代码质量检查
code-quality:
runs-on: ubuntu-latest
steps:
- name: 检出代码
uses: actions/checkout@v3
- name: 设置PHP环境
uses: shivammathur/setup-php@v2
with:
php-version: '8.0'
extensions: mbstring, xml, ctype, iconv, intl, pdo_mysql
coverage: xdebug
- name: 验证Composer配置
run: composer validate --strict
- name: 安装依赖
run: composer install --prefer-dist --no-progress
- name: PHP代码风格检查
run: composer run phpcs
- name: 静态分析
run: composer run phpstan
- name: 安全漏洞扫描
run: composer run security-check
# 单元测试与集成测试
test:
runs-on: ubuntu-latest
needs: code-quality
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wordpress_test
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: 检出代码
uses: actions/checkout@v3
- name: 设置PHP环境
uses: shivammathur/setup-php@v2
with:
php-version: '8.0'
extensions: mbstring, xml, ctype, iconv, intl, pdo_mysql
coverage: xdebug
- name: 安装WordPress测试框架
run: |
bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 latest true
- name: 运行单元测试
run: composer run test-unit
env:
WP_TESTS_DIR: /tmp/wordpress-tests-lib
- name: 运行集成测试
run: composer run test-integration
- name: 生成测试覆盖率报告
run: composer run test-coverage
- name: 上传测试结果
uses: actions/upload-artifact@v3
with:
name: test-results
path: tests/_output/
# 构建与部署
deploy:
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main'
steps:
- name: 检出代码
uses: actions/checkout@v3
- name: 设置部署环境变量
run: |
echo "DEPLOY_TIME=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV
- name: 构建Docker镜像
run: |
docker build -t supply-chain-plugin:latest .
docker tag supply-chain-plugin:latest your-registry/supply-chain-plugin:${{ env.DEPLOY_TIME }}
- name: 推送Docker镜像
run: |
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
docker push your-registry/supply-chain-plugin:${{ env.DEPLOY_TIME }}
- name: 部署到生产环境
run: |
# 使用SSH连接到生产服务器并部署
echo "${{ secrets.SSH_PRIVATE_KEY }}" > private_key
chmod 600 private_key
ssh -o StrictHostKeyChecking=no -i private_key
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}
"cd /var/www/supply-chain && ./deploy.sh ${{ env.DEPLOY_TIME }}"
2.2 WordPress插件自动化测试示例
以下是一个供应链管理插件的测试示例:
<?php
/**
* 供应链库存管理测试类
*
* @package SupplyChainTests
*/
use PHPUnitFrameworkTestCase;
/**
* 库存管理测试类
*/
class InventoryManagerTest extends TestCase
{
/**
* 测试库存初始化
*/
public function testInventoryInitialization()
{
$inventory = new InventoryManager();
// 测试空库存
$this->assertEquals(0, $inventory->getTotalItems());
// 添加测试产品
$product = [
'id' => 1,
'name' => '测试产品',
'sku' => 'TEST-001',
'quantity' => 100,
'reorder_level' => 20
];
$result = $inventory->addProduct($product);
$this->assertTrue($result);
$this->assertEquals(1, $inventory->getTotalItems());
$this->assertEquals(100, $inventory->getProductQuantity(1));
}
/**
* 测试库存更新
*/
public function testInventoryUpdate()
{
$inventory = new InventoryManager();
// 初始化库存
$inventory->addProduct([
'id' => 1,
'name' => '测试产品',
'sku' => 'TEST-001',
'quantity' => 50,
'reorder_level' => 10
]);
// 测试增加库存
$inventory->updateQuantity(1, 25);
$this->assertEquals(75, $inventory->getProductQuantity(1));
// 测试减少库存
$inventory->updateQuantity(1, -30);
$this->assertEquals(45, $inventory->getProductQuantity(1));
// 测试库存不足
$this->expectException(InsufficientInventoryException::class);
$inventory->updateQuantity(1, -100);
}
/**
* 测试重新订购逻辑
*/
public function testReorderLogic()
{
$inventory = new InventoryManager();
// 添加低于重新订购水平的产品
$inventory->addProduct([
'id' => 1,
'name' => '测试产品',
'sku' => 'TEST-001',
'quantity' => 5,
'reorder_level' => 10,
'reorder_quantity' => 50
]);
// 检查是否需要重新订购
$productsToReorder = $inventory->getProductsNeedingReorder();
$this->assertCount(1, $productsToReorder);
$this->assertEquals(1, $productsToReorder[0]['product_id']);
// 执行重新订购
$orderId = $inventory->processReorder(1);
$this->assertIsInt($orderId);
$this->assertGreaterThan(0, $orderId);
// 验证库存已更新
$this->assertEquals(55, $inventory->getProductQuantity(1));
}
}
/**
* 库存管理类
*/
class InventoryManager
{
private $inventory = [];
/**
* 添加产品到库存
*
* @param array $product 产品数据
* @return bool 添加是否成功
*/
public function addProduct(array $product): bool
{
// 验证必需字段
$requiredFields = ['id', 'name', 'sku', 'quantity'];
foreach ($requiredFields as $field) {
if (!isset($product[$field])) {
throw new InvalidArgumentException("缺少必需字段: {$field}");
}
}
$this->inventory[$product['id']] = [
'id' => $product['id'],
'name' => $product['name'],
'sku' => $product['sku'],
'quantity' => (int)$product['quantity'],
'reorder_level' => $product['reorder_level'] ?? 0,
'reorder_quantity' => $product['reorder_quantity'] ?? 0
];
return true;
}
/**
* 获取产品数量
*
* @param int $productId 产品ID
* @return int 产品数量
*/
public function getProductQuantity(int $productId): int
{
if (!isset($this->inventory[$productId])) {
throw new InvalidArgumentException("产品不存在: {$productId}");
}
return $this->inventory[$productId]['quantity'];
}
/**
* 更新产品数量
*
* @param int $productId 产品ID
* @param int $delta 数量变化(正数增加,负数减少)
* @return bool 更新是否成功
*/
public function updateQuantity(int $productId, int $delta): bool
{
if (!isset($this->inventory[$productId])) {
throw new InvalidArgumentException("产品不存在: {$productId}");
}
$newQuantity = $this->inventory[$productId]['quantity'] + $delta;
if ($newQuantity < 0) {
throw new InsufficientInventoryException(
"库存不足。产品ID: {$productId}, 当前库存: {$this->inventory[$productId]['quantity']}, 需求: " . abs($delta)
);
}
$this->inventory[$productId]['quantity'] = $newQuantity;
return true;
}
/**
* 获取需要重新订购的产品
*
* @return array 需要重新订购的产品列表
*/
public function getProductsNeedingReorder(): array
{
$products = [];
foreach ($this->inventory as $product) {
if ($product['reorder_level'] > 0 &&
$product['quantity'] <= $product['reorder_level'] &&
$product['reorder_quantity'] > 0) {
$products[] = [
'product_id' => $product['id'],
'product_name' => $product['name'],
'current_quantity' => $product['quantity'],
'reorder_level' => $product['reorder_level'],
'reorder_quantity' => $product['reorder_quantity']
];
}
}
return $products;
}
/**
* 获取总产品数量
*
* @return int 总产品数量
*/
public function getTotalItems(): int
{
return count($this->inventory);
}
}
/**
* 库存不足异常类
*/
class InsufficientInventoryException extends Exception
{
// 自定义异常类
}
?>
自动化部署策略
3.1 蓝绿部署配置
蓝绿部署可以最小化部署风险,确保供应链系统的持续可用性。
#!/bin/bash
# deploy.sh - 蓝绿部署脚本
set -e
DEPLOY_VERSION=$1
BLUE_DIR="/var/www/supply-chain-blue"
GREEN_DIR="/var/www/supply-chain-green"
CURRENT_LINK="/var/www/supply-chain-current"
NGINX_CONFIG="/etc/nginx/sites-available/supply-chain"
# 检查当前活动环境
if [ -L "$CURRENT_LINK" ]; then
CURRENT_ENV=$(readlink -f "$CURRENT_LINK")
if [[ "$CURRENT_ENV" == *"-blue" ]]; then
ACTIVE="blue"
STANDBY="green"
STANDBY_DIR="$GREEN_DIR"
else
ACTIVE="green"
STANDBY="blue"
STANDBY_DIR="$BLUE_DIR"
fi
else
# 首次部署
ACTIVE="blue"
STANDBY="green"
STANDBY_DIR="$GREEN_DIR"
fi
echo "当前活动环境: $ACTIVE"
echo "准备部署到备用环境: $STANDBY"
# 准备备用环境目录
if [ ! -d "$STANDBY_DIR" ]; then
mkdir -p "$STANDBY_DIR"
fi
# 拉取新版本Docker镜像
echo "拉取版本 $DEPLOY_VERSION 的Docker镜像..."
docker pull your-registry/supply-chain-plugin:$DEPLOY_VERSION
# 停止备用环境容器
cd "$STANDBY_DIR"
docker-compose down || true
# 更新环境变量
echo "DEPLOY_VERSION=$DEPLOY_VERSION" > .env
echo "DB_HOST=supply-chain-db" >> .env
echo "DB_NAME=supply_chain_$STANDBY" >> .env
# 启动备用环境
docker-compose up -d
# 等待服务就绪
echo "等待 $STANDBY 环境就绪..."
for i in {1..30}; do
if curl -f http://localhost:8080/health-check > /dev/null 2>&1; then
echo "$STANDBY 环境已就绪"
break
fi
sleep 2
done
# 运行数据库迁移
echo "运行数据库迁移..."
docker-compose exec -T wordpress php wp-content/plugins/supply-chain/migrations/migrate.php
# 运行健康检查
echo "运行健康检查..."
HEALTH_CHECK_RESULT=$(docker-compose exec -T wordpress curl -s http://localhost/health-check)
自动化部署策略(续)
3.1 蓝绿部署配置(续)
echo "健康检查失败: $HEALTH_CHECK_RESULT"
exit 1
fi
# 切换流量到新环境
echo "切换流量到 $STANDBY 环境..."
ln -sfn "$STANDBY_DIR" "$CURRENT_LINK"
# 重新加载Nginx配置
nginx -s reload
echo "流量切换完成,新环境已激活"
# 运行自动化测试验证新环境
echo "运行自动化测试验证新环境..."
docker-compose exec -T wordpress php vendor/bin/phpunit
--testsuite production
--configuration phpunit.production.xml
# 清理旧环境(可选,保留一段时间用于回滚)
echo "清理旧环境..."
OLD_ENV_DIR=$([ "$STANDBY" = "blue" ] && echo "$GREEN_DIR" || echo "$BLUE_DIR")
cd "$OLD_ENV_DIR"
docker-compose down
echo "部署完成!版本 $DEPLOY_VERSION 已成功上线"
3.2 数据库迁移管理
在供应链系统中,数据库结构可能频繁变更。以下是数据库迁移管理脚本:
<?php
/**
* 供应链数据库迁移管理器
*
* @package SupplyChainMigrations
*/
class MigrationManager
{
private $wpdb;
private $migrations_table = 'supply_chain_migrations';
public function __construct()
{
global $wpdb;
$this->wpdb = $wpdb;
$this->createMigrationsTable();
}
/**
* 创建迁移记录表
*/
private function createMigrationsTable()
{
$charset_collate = $this->wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS {$this->wpdb->prefix}{$this->migrations_table} (
id bigint(20) NOT NULL AUTO_INCREMENT,
migration_name varchar(255) NOT NULL,
batch int(11) NOT NULL,
applied_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY migration_name (migration_name)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
/**
* 运行所有待处理的迁移
*/
public function runMigrations()
{
$applied_migrations = $this->getAppliedMigrations();
$migration_files = $this->getMigrationFiles();
$new_migrations = array_diff($migration_files, $applied_migrations);
if (empty($new_migrations)) {
return ['success' => true, 'message' => '没有需要运行的迁移'];
}
sort($new_migrations);
$batch = $this->getNextBatchNumber();
foreach ($new_migrations as $migration) {
try {
$this->runMigration($migration, $batch);
error_log("迁移成功: $migration");
} catch (Exception $e) {
error_log("迁移失败: $migration - " . $e->getMessage());
return ['success' => false, 'message' => "迁移失败: $migration"];
}
}
return ['success' => true, 'message' => '所有迁移已成功运行'];
}
/**
* 运行单个迁移
*/
private function runMigration($migration_name, $batch)
{
$migration_file = SUPPLY_CHAIN_PLUGIN_DIR . "/migrations/{$migration_name}.php";
if (!file_exists($migration_file)) {
throw new Exception("迁移文件不存在: {$migration_file}");
}
require_once($migration_file);
$class_name = $this->getClassNameFromFileName($migration_name);
if (!class_exists($class_name)) {
throw new Exception("迁移类不存在: {$class_name}");
}
$migration = new $class_name($this->wpdb);
// 开始事务
$this->wpdb->query('START TRANSACTION');
try {
$migration->up();
// 记录迁移
$this->wpdb->insert(
$this->wpdb->prefix . $this->migrations_table,
[
'migration_name' => $migration_name,
'batch' => $batch
]
);
$this->wpdb->query('COMMIT');
} catch (Exception $e) {
$this->wpdb->query('ROLLBACK');
throw $e;
}
}
/**
* 回滚迁移
*/
public function rollback($steps = 1)
{
$last_batch = $this->getLastBatch();
$migrations_to_rollback = $this->wpdb->get_results(
$this->wpdb->prepare(
"SELECT migration_name FROM {$this->wpdb->prefix}{$this->migrations_table}
WHERE batch = %d ORDER BY id DESC",
$last_batch
)
);
if (empty($migrations_to_rollback)) {
return ['success' => true, 'message' => '没有需要回滚的迁移'];
}
foreach ($migrations_to_rollback as $migration) {
try {
$this->rollbackMigration($migration->migration_name);
error_log("回滚成功: {$migration->migration_name}");
} catch (Exception $e) {
error_log("回滚失败: {$migration->migration_name} - " . $e->getMessage());
return ['success' => false, 'message' => "回滚失败: {$migration->migration_name}"];
}
}
return ['success' => true, 'message' => '回滚完成'];
}
/**
* 获取迁移文件列表
*/
private function getMigrationFiles()
{
$files = glob(SUPPLY_CHAIN_PLUGIN_DIR . '/migrations/*.php');
return array_map('basename', $files);
}
/**
* 获取已应用的迁移
*/
private function getAppliedMigrations()
{
$results = $this->wpdb->get_col(
"SELECT migration_name FROM {$this->wpdb->prefix}{$this->migrations_table}"
);
return $results ?: [];
}
}
/**
* 示例迁移文件:创建库存表
* 文件路径:migrations/2023_10_01_000001_create_inventory_table.php
*/
class CreateInventoryTable
{
private $wpdb;
public function __construct($wpdb)
{
$this->wpdb = $wpdb;
}
public function up()
{
$charset_collate = $this->wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS {$this->wpdb->prefix}supply_chain_inventory (
id bigint(20) NOT NULL AUTO_INCREMENT,
product_id bigint(20) NOT NULL,
sku varchar(100) NOT NULL,
product_name varchar(255) NOT NULL,
quantity int(11) NOT NULL DEFAULT 0,
reorder_level int(11) NOT NULL DEFAULT 0,
reorder_quantity int(11) NOT NULL DEFAULT 0,
location varchar(100),
last_updated datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY sku (sku),
KEY product_id (product_id),
KEY location (location)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// 添加初始数据
$this->wpdb->insert(
$this->wpdb->prefix . 'supply_chain_inventory',
[
'product_id' => 1,
'sku' => 'DEFAULT-001',
'product_name' => '默认产品',
'quantity' => 100,
'reorder_level' => 20,
'reorder_quantity' => 50,
'location' => '主仓库'
]
);
}
public function down()
{
$sql = "DROP TABLE IF EXISTS {$this->wpdb->prefix}supply_chain_inventory";
$this->wpdb->query($sql);
}
}
?>
监控与日志管理
4.1 应用性能监控配置
<?php
/**
* 供应链系统监控配置
*
* @package SupplyChainMonitoring
*/
class SupplyChainMonitor
{
private $metrics = [];
private $log_file;
public function __construct()
{
$upload_dir = wp_upload_dir();
$this->log_file = $upload_dir['basedir'] . '/supply-chain-logs/monitor.log';
// 确保日志目录存在
wp_mkdir_p(dirname($this->log_file));
// 注册关闭函数,确保指标被记录
register_shutdown_function([$this, 'logMetrics']);
}
/**
* 记录性能指标
*/
public function recordMetric($name, $value, $labels = [])
{
$this->metrics[] = [
'timestamp' => microtime(true),
'name' => $name,
'value' => $value,
'labels' => $labels
];
}
/**
* 记录API响应时间
*/
public function recordApiResponseTime($endpoint, $response_time)
{
$this->recordMetric('api_response_time', $response_time, [
'endpoint' => $endpoint,
'method' => $_SERVER['REQUEST_METHOD'] ?? 'CLI'
]);
}
/**
* 记录数据库查询性能
*/
public function recordQueryPerformance($query, $execution_time)
{
// 简化查询用于记录
$simplified_query = preg_replace('/s+/', ' ', $query);
$simplified_query = substr($simplified_query, 0, 200);
$this->recordMetric('db_query_time', $execution_time, [
'query_type' => $this->getQueryType($query),
'query_hash' => md5($query)
]);
}
/**
* 记录库存操作
*/
public function recordInventoryOperation($operation, $product_id, $quantity, $success)
{
$this->recordMetric('inventory_operation', 1, [
'operation' => $operation,
'product_id' => $product_id,
'quantity' => $quantity,
'success' => $success ? 'true' : 'false'
]);
}
/**
* 将指标记录到文件
*/
public function logMetrics()
{
if (empty($this->metrics)) {
return;
}
$log_data = [
'timestamp' => date('Y-m-d H:i:s'),
'metrics' => $this->metrics,
'memory_usage' => memory_get_peak_usage(true) / 1024 / 1024, // MB
'execution_time' => microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']
];
$log_line = json_encode($log_data) . PHP_EOL;
// 使用文件锁避免并发写入问题
$fp = fopen($this->log_file, 'a');
if (flock($fp, LOCK_EX)) {
fwrite($fp, $log_line);
flock($fp, LOCK_UN);
}
fclose($fp);
// 发送到外部监控系统(可选)
$this->sendToExternalMonitor($log_data);
}
/**
* 发送指标到外部监控系统
*/
private function sendToExternalMonitor($data)
{
// 发送到Prometheus Pushgateway
if (defined('PROMETHEUS_PUSHGATEWAY_URL')) {
$metrics = [];
foreach ($data['metrics'] as $metric) {
$metric_name = str_replace('.', '_', $metric['name']);
$labels = '';
if (!empty($metric['labels'])) {
$label_parts = [];
foreach ($metric['labels'] as $key => $value) {
$label_parts[] = $key . '="' . addslashes($value) . '"';
}
$labels = '{' . implode(',', $label_parts) . '}';
}
$metrics[] = "supply_chain_{$metric_name}{$labels} {$metric['value']}";
}
if (!empty($metrics)) {
$ch = curl_init(PROMETHEUS_PUSHGATEWAY_URL);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, implode("n", $metrics));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
}
}
}
/**
* 获取查询类型
*/
private function getQueryType($query)
{
$query = strtoupper(trim($query));
if (strpos($query, 'SELECT') === 0) return 'SELECT';
if (strpos($query, 'INSERT') === 0) return 'INSERT';
if (strpos($query, 'UPDATE') === 0) return 'UPDATE';
if (strpos($query, 'DELETE') === 0) return 'DELETE';
return 'OTHER';
}
}
/**
* 日志轮转管理
*/
class LogRotator
{
public static function rotateLogs($log_dir, $max_files = 30, $max_size_mb = 100)
{
$files = glob($log_dir . '/*.log');
foreach ($files as $file) {
// 检查文件大小
if (filesize($file) > $max_size_mb * 1024 * 1024) {
self::rotateSingleFile($file, $max_files);
}
}
}
private static function rotateSingleFile($file, $max_files)
{
// 压缩并重命名当前日志文件
$timestamp = date('Ymd_His');
$rotated_file = $file . '.' . $timestamp . '.gz';
// 压缩文件
$fp = gzopen($rotated_file, 'w9');
if ($fp) {
gzwrite($fp, file_get_contents($file));
gzclose($fp);
// 清空原文件
file_put_contents($file, '');
// 清理旧日志文件
self::cleanupOldFiles(dirname($file), $max_files);
}
}
private static function cleanupOldFiles($log_dir, $max_files)
{
$files = glob($log_dir . '/*.gz');
// 按修改时间排序
usort($files, function($a, $b) {
return filemtime($b) - filemtime($a);
});
// 删除超出数量限制的文件
if (count($files) > $max_files) {
$files_to_delete = array_slice($files, $max_files);
foreach ($files_to_delete as $file) {
unlink($file);
}
}
}
}
?>
安全与合规性检查
5.1 自动化安全扫描
# .github/workflows/security-scan.yml
name: 安全扫描
on:
schedule:
- cron: '0 2 * * *' # 每天凌晨2点运行
push:
branches: [ main ]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: 检出代码
uses: actions/checkout@v3
- name: 运行OWASP ZAP安全扫描
uses: zaproxy/action-full-scan@v0.7.0
with:
target: 'http://localhost:8080'
rules_file_name: '.zap/rules.tsv'
cmd_options: '-a'
- name: 运行依赖漏洞扫描
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
- name: 运行WordPress安全扫描
run: |
docker run --rm
-v $(pwd):/app
wpscan/wpscan
--url http://localhost:8080
--enumerate vp,vt
--api-token ${{ secrets.WPSCAN_API_TOKEN }}
--format json
--output wpscan-report.json
- name: 上传安全报告
uses: actions/upload-artifact@v3
with:
name: security-reports
path: |
*.json
*.html
*.xml
5.2 合规性检查脚本
<?php
/**
* 供应链系统合规性检查
*
* @package SupplyChainCompliance
*/
class ComplianceChecker
{
/**
* 检查GDPR合规性
*/
public function checkGDPRCompliance()
{
$checks = [
'data_encryption' => $this->checkDataEncryption(),
'data_retention' => $this->checkDataRetentionPolicy(),
'user_consent' => $this->checkUserConsentMechanism(),
'data_export' => $this->checkDataExportCapability(),
'data_deletion' => $this->checkDataDeletionCapability()
];
return [
'compliant' => !in_array(false, $checks, true),
'checks' => $checks,
'timestamp' => current_time('mysql')
];
}
/**
* 检查PCIDSS合规性(如果处理支付信息)
*/
public function checkPCIDSSCompliance()
{
