feat(redcap): REDCap 15.8.0 Docker本地开发环境部署完成

核心成果:
- REDCap 15.8.0成功部署在Docker环境
- 登录功能正常,管理员账户: Admin/Admin123!
- MySQL 8.0 + PHP 8.1 + Apache 2.4环境验证通过

问题解决:
1. 修复ERR_CONTENT_DECODING_FAILED错误
   - 强制禁用Apache deflate模块
   - PHP配置关闭zlib.output_compression
   - 自动注释REDCap源码中的压缩设置

2. 修复Base URL配置错误
   - 更新redcap_config表中的redcap_base_url
   - 统一DocumentRoot与访问路径

3. 修复登录失败问题(CRLF污染)
   - 删除database.php末尾的PHP结束标签
   - 创建.gitattributes规范换行符
   - 验证REDCap官方源码无此问题

技术改进:
- 添加密码重置工具脚本
- 完善docker-entrypoint.sh启动脚本
- 创建详细的部署问题解决记录
- 建立PHP配置文件最佳实践

部署文档:
- REDCap本地Docker开发环境部署方案
- REDCap生产环境部署决策报告(ECS vs SAE)
- 部署问题解决记录(含根因分析)

下一步:
- Day 2: 开发REDCap API Adapter
- 实现与IIT Manager Agent的数据对接
This commit is contained in:
2026-01-02 10:02:46 +08:00
parent dac3cecf78
commit 38d9bf99d6
25 changed files with 3990 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env pwsh
# REDCap Docker环境清理脚本
# 版本v1.0
# 日期2026-01-01
# ⚠️ 警告:此脚本会删除所有数据!
Write-Host "🗑️ REDCap Docker环境清理" -ForegroundColor Red
Write-Host ""
Write-Host "⚠️ 警告:此操作将删除所有数据!" -ForegroundColor Red
Write-Host " • 容器将被删除" -ForegroundColor Yellow
Write-Host " • 数据卷将被删除(包括数据库、上传文件)" -ForegroundColor Yellow
Write-Host " • Docker镜像将被删除" -ForegroundColor Yellow
Write-Host ""
# 切换到项目目录
$ScriptDir = Split-Path -Parent $PSCommandPath
$ProjectDir = Split-Path -Parent $ScriptDir
Set-Location $ProjectDir
# 二次确认
$confirm1 = Read-Host "确认要删除所有数据吗?(输入 YES 继续)"
if ($confirm1 -ne "YES") {
Write-Host "❌ 清理已取消。" -ForegroundColor Yellow
exit 0
}
Write-Host ""
$confirm2 = Read-Host "最后确认:真的要删除所有数据吗?(再次输入 YES)"
if ($confirm2 -ne "YES") {
Write-Host "❌ 清理已取消。" -ForegroundColor Yellow
exit 0
}
Write-Host ""
Write-Host "🗑️ 开始清理..." -ForegroundColor Yellow
Write-Host ""
# 停止并删除容器
Write-Host " 1. 停止并删除容器..." -ForegroundColor Gray
docker-compose down
# 删除数据卷
Write-Host " 2. 删除数据卷..." -ForegroundColor Gray
docker-compose down --volumes
# 删除镜像
Write-Host " 3. 删除Docker镜像..." -ForegroundColor Gray
$images = docker images --filter=reference="redcap-docker-dev*" -q
if ($images) {
docker rmi $images 2>&1 | Out-Null
}
# 显示Docker卷列表
Write-Host " 4. 验证清理结果..." -ForegroundColor Gray
Write-Host ""
Write-Host "剩余的REDCap相关卷" -ForegroundColor Cyan
docker volume ls | Select-String "redcap"
Write-Host ""
Write-Host "============================================" -ForegroundColor Green
Write-Host " ✅ 清理完成!" -ForegroundColor Green
Write-Host "============================================" -ForegroundColor Green
Write-Host ""
Write-Host "💡 提示:" -ForegroundColor Cyan
Write-Host " • 如需重新部署:.\scripts\setup-redcap.ps1" -ForegroundColor Gray
Write-Host " • 数据已完全删除,无法恢复" -ForegroundColor Gray
Write-Host ""

View File

@@ -0,0 +1,47 @@
<?php
/**
* REDCap密码哈希生成脚本
* 直接在数据库中更新Admin密码
*/
// REDCap密码哈希算法SHA-512 + Salt
$username = 'Admin';
$new_password = 'Admin123!';
// 生成新的saltREDCap使用100字符的随机salt
$salt = '';
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+[]{}|;:,.<>?~';
for ($i = 0; $i < 100; $i++) {
$salt .= $characters[random_int(0, strlen($characters) - 1)];
}
// 生成密码哈希SHA-512(password + salt)
$password_hash = hash('sha512', $new_password . $salt);
// 数据库连接信息
$db_host = getenv('REDCAP_DB_HOST') ?: 'redcap-mysql';
$db_name = getenv('REDCAP_DB_NAME') ?: 'redcap';
$db_user = getenv('REDCAP_DB_USER') ?: 'redcap_user';
$db_pass = getenv('REDCAP_DB_PASS') ?: 'redcap_pass_dev_456';
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 更新密码
$stmt = $pdo->prepare("UPDATE redcap_auth SET password = ?, password_salt = ? WHERE username = ?");
$result = $stmt->execute([$password_hash, $salt, $username]);
if ($result) {
echo "✅ Password updated successfully!\n\n";
echo "Username: $username\n";
echo "New Password: $new_password\n\n";
echo "You can now login at: http://localhost:8080/\n";
} else {
echo "❌ Failed to update password\n";
}
} catch (PDOException $e) {
echo "❌ Database error: " . $e->getMessage() . "\n";
}

View File

@@ -0,0 +1,60 @@
#!/usr/bin/env pwsh
# REDCap Docker日志查看脚本
# 版本v1.0
# 日期2026-01-01
param(
[string]$Service = "", # 指定服务名redcap-web, redcap-db, phpmyadmin
[switch]$Follow, # 实时跟踪日志
[int]$Tail = 50 # 显示最近N行日志
)
Write-Host "📝 REDCap Docker日志" -ForegroundColor Cyan
Write-Host ""
# 切换到项目目录
$ScriptDir = Split-Path -Parent $PSCommandPath
$ProjectDir = Split-Path -Parent $ScriptDir
Set-Location $ProjectDir
# 构建docker-compose logs命令
$logCmd = "docker-compose logs"
if ($Follow) {
$logCmd += " -f"
} else {
$logCmd += " --tail=$Tail"
}
if ($Service) {
$logCmd += " $Service"
Write-Host "查看服务:$Service" -ForegroundColor Yellow
} else {
Write-Host "查看所有服务日志" -ForegroundColor Yellow
}
if ($Follow) {
Write-Host "实时跟踪模式按Ctrl+C退出" -ForegroundColor Gray
} else {
Write-Host "显示最近 $Tail 行日志" -ForegroundColor Gray
}
Write-Host ""
Write-Host "============================================" -ForegroundColor Gray
# 执行命令
Invoke-Expression $logCmd
Write-Host ""
Write-Host "💡 提示:" -ForegroundColor Cyan
Write-Host " • 查看特定服务:.\scripts\logs-redcap.ps1 -Service redcap-web" -ForegroundColor Gray
Write-Host " • 实时跟踪:.\scripts\logs-redcap.ps1 -Follow" -ForegroundColor Gray
Write-Host " • 显示更多行:.\scripts\logs-redcap.ps1 -Tail 100" -ForegroundColor Gray
Write-Host ""
Write-Host "可用服务名:" -ForegroundColor Cyan
Write-Host " • redcap-webREDCap Web服务" -ForegroundColor Gray
Write-Host " • redcap-dbMySQL数据库" -ForegroundColor Gray
Write-Host " • phpmyadmin数据库管理工具" -ForegroundColor Gray
Write-Host ""

View File

@@ -0,0 +1,23 @@
<?php
/**
* REDCap Admin密码重置脚本
* 用途重置Admin用户密码
*/
require_once '/var/www/html/redcap/redcap_connect.php';
require_once APP_PATH_CLASSES . 'Authentication.php';
$username = 'Admin';
$new_password = 'Admin123!';
echo "Resetting password for user: $username\n";
$result = Authentication::setPassword($username, $new_password, true);
if ($result) {
echo "✅ Password reset successful!\n";
echo "Username: Admin\n";
echo "New Password: Admin123!\n";
} else {
echo "❌ Password reset failed!\n";
}

View File

@@ -0,0 +1,161 @@
# REDCap Docker一键部署脚本
param([switch]$SkipCheck, [switch]$Force)
Write-Host "============================================" -ForegroundColor Cyan
Write-Host " REDCap Docker环境一键部署脚本" -ForegroundColor Cyan
Write-Host "============================================" -ForegroundColor Cyan
Write-Host ""
$ScriptDir = Split-Path -Parent $PSCommandPath
$ProjectDir = Split-Path -Parent $ScriptDir
Set-Location $ProjectDir
Write-Host "工作目录: $ProjectDir" -ForegroundColor Green
Write-Host ""
# 步骤 1: 环境检查
if (-not $SkipCheck) {
Write-Host "步骤 1/7: 环境检查..." -ForegroundColor Yellow
Write-Host " 检查Docker..." -NoNewline
$null = docker --version 2>&1
if ($LASTEXITCODE -ne 0) {
Write-Host " X" -ForegroundColor Red
Write-Host "Docker未安装或未运行!" -ForegroundColor Red
exit 1
}
Write-Host " OK" -ForegroundColor Green
Write-Host " 检查Docker Compose..." -NoNewline
$null = docker-compose --version 2>&1
if ($LASTEXITCODE -ne 0) {
Write-Host " X" -ForegroundColor Red
Write-Host "Docker Compose未安装!" -ForegroundColor Red
exit 1
}
Write-Host " OK" -ForegroundColor Green
Write-Host " 检查REDCap源码..." -NoNewline
if (-not (Test-Path "..\redcap15.8.0\redcap\index.php")) {
Write-Host " X" -ForegroundColor Red
Write-Host "REDCap源码未找到!" -ForegroundColor Red
exit 1
}
Write-Host " OK" -ForegroundColor Green
Write-Host "环境检查通过!" -ForegroundColor Green
Write-Host ""
}
# 步骤 2: 创建.env文件
Write-Host "步骤 2/7: 配置环境变量..." -ForegroundColor Yellow
$envExists = Test-Path ".env"
if (-not $envExists) {
Write-Host " 从模板创建.env文件..." -ForegroundColor Gray
$templateExists = Test-Path "env.template"
if (-not $templateExists) {
Write-Host " 未找到env.template!" -ForegroundColor Red
exit 1
}
Copy-Item "env.template" ".env"
Write-Host " .env文件已创建" -ForegroundColor Green
}
if ($envExists) {
Write-Host " .env文件已存在" -ForegroundColor Green
}
Write-Host ""
# 步骤 3: 检查端口
Write-Host "步骤 3/7: 检查端口占用..." -ForegroundColor Yellow
$ports = @(8080, 3306, 8081)
$portsInUse = @()
foreach ($port in $ports) {
$check = netstat -ano | Select-String ":$port " | Select-Object -First 1
if ($check) {
Write-Host " 端口 $port 已被占用" -ForegroundColor Yellow
$portsInUse += $port
continue
}
Write-Host " 端口 $port 可用" -ForegroundColor Green
}
if ($portsInUse.Count -gt 0) {
Write-Host ""
Write-Host "警告: 部分端口被占用!" -ForegroundColor Yellow
if (-not $Force) {
$continue = Read-Host "是否继续? (Y/N)"
if ($continue -ne "Y") {
Write-Host "部署已取消" -ForegroundColor Yellow
exit 0
}
}
}
Write-Host ""
# 步骤 4: 清理旧容器
if ($Force) {
Write-Host "步骤 4/7: 清理旧容器..." -ForegroundColor Yellow
docker-compose down 2>&1 | Out-Null
Write-Host " 旧容器已清理" -ForegroundColor Green
Write-Host ""
}
if (-not $Force) {
Write-Host "步骤 4/7: 跳过清理 (使用 -Force 强制清理)" -ForegroundColor Gray
Write-Host ""
}
# 步骤 5: 构建镜像
Write-Host "步骤 5/7: 构建Docker镜像..." -ForegroundColor Yellow
Write-Host " 这可能需要几分钟..." -ForegroundColor Gray
Write-Host ""
docker-compose build
if ($LASTEXITCODE -ne 0) {
Write-Host "Docker镜像构建失败!" -ForegroundColor Red
exit 1
}
Write-Host ""
Write-Host "Docker镜像构建成功!" -ForegroundColor Green
Write-Host ""
# 步骤 6: 启动容器
Write-Host "步骤 6/7: 启动容器..." -ForegroundColor Yellow
docker-compose up -d
if ($LASTEXITCODE -ne 0) {
Write-Host "容器启动失败!" -ForegroundColor Red
exit 1
}
Write-Host "容器启动成功!" -ForegroundColor Green
Write-Host ""
# 步骤 7: 等待服务就绪
Write-Host "步骤 7/7: 等待服务就绪..." -ForegroundColor Yellow
Write-Host " 等待MySQL启动 (30秒)..." -ForegroundColor Gray
Start-Sleep -Seconds 30
Write-Host ""
Write-Host "容器状态:" -ForegroundColor Cyan
docker-compose ps
# 部署完成
Write-Host ""
Write-Host "============================================" -ForegroundColor Green
Write-Host " REDCap Docker环境部署完成!" -ForegroundColor Green
Write-Host "============================================" -ForegroundColor Green
Write-Host ""
Write-Host "服务访问地址:" -ForegroundColor Cyan
Write-Host " REDCap: http://localhost:8080" -ForegroundColor White
Write-Host " phpMyAdmin: http://localhost:8081" -ForegroundColor White
Write-Host ""
Write-Host "下一步操作:" -ForegroundColor Cyan
Write-Host " 1. 访问 http://localhost:8080/install.php" -ForegroundColor White
Write-Host " 2. 数据库配置:" -ForegroundColor White
Write-Host " Host: redcap-db" -ForegroundColor Gray
Write-Host " Database: redcap" -ForegroundColor Gray
Write-Host " User: redcap_user" -ForegroundColor Gray
Write-Host " Password: redcap_pass_dev_456" -ForegroundColor Gray
Write-Host ""

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env pwsh
# REDCap Docker环境启动脚本
# 版本v1.0
# 日期2026-01-01
Write-Host "🚀 启动REDCap Docker环境..." -ForegroundColor Cyan
Write-Host ""
# 切换到项目目录
$ScriptDir = Split-Path -Parent $PSCommandPath
$ProjectDir = Split-Path -Parent $ScriptDir
Set-Location $ProjectDir
# 检查Docker是否运行
$dockerRunning = docker info 2>&1 | Select-String "Server Version"
if (-not $dockerRunning) {
Write-Host "❌ Docker未运行。请先启动Docker Desktop。" -ForegroundColor Red
exit 1
}
# 启动容器
docker-compose up -d
if ($LASTEXITCODE -eq 0) {
Write-Host ""
Write-Host "⏳ 等待服务就绪10秒..." -ForegroundColor Yellow
Start-Sleep -Seconds 10
Write-Host ""
Write-Host "✅ REDCap环境已启动" -ForegroundColor Green
Write-Host ""
Write-Host "📋 服务访问地址:" -ForegroundColor Cyan
Write-Host " • REDCap http://localhost:8080" -ForegroundColor White
Write-Host " • phpMyAdmin http://localhost:8081" -ForegroundColor White
Write-Host ""
Write-Host "📊 容器状态:" -ForegroundColor Cyan
docker-compose ps
Write-Host ""
} else {
Write-Host "❌ 启动失败!" -ForegroundColor Red
Write-Host "请检查日志:.\scripts\logs-redcap.ps1" -ForegroundColor Yellow
exit 1
}

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env pwsh
# REDCap Docker环境停止脚本
# 版本v1.0
# 日期2026-01-01
Write-Host "⏹️ 停止REDCap Docker环境..." -ForegroundColor Yellow
Write-Host ""
# 切换到项目目录
$ScriptDir = Split-Path -Parent $PSCommandPath
$ProjectDir = Split-Path -Parent $ScriptDir
Set-Location $ProjectDir
# 停止容器(保留数据)
docker-compose stop
if ($LASTEXITCODE -eq 0) {
Write-Host ""
Write-Host "✅ REDCap环境已停止" -ForegroundColor Green
Write-Host ""
Write-Host "💡 提示:" -ForegroundColor Cyan
Write-Host " • 数据已保留在Docker卷中" -ForegroundColor Gray
Write-Host " • 重新启动:.\scripts\start-redcap.ps1" -ForegroundColor Gray
Write-Host " • 完全清理(删除数据):.\scripts\clean-redcap.ps1" -ForegroundColor Gray
Write-Host ""
} else {
Write-Host "❌ 停止失败!" -ForegroundColor Red
exit 1
}