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,59 @@
# **REDCap ERR\_CONTENT\_DECODING\_FAILED 错误排查与修复指南**
如果在浏览器访问 REDCap 时遇到 net::ERR\_CONTENT\_DECODING\_FAILED 200 (OK),说明数据包在传输过程中被“弄脏”了。以下是按优先级排序的 4 种解决方案:
## **1\. 禁用 PHP 的 zlib 输出压缩 (最常见原因)**
REDCap 内部有时会尝试自己控制输出压缩,如果你的 php.ini 里也开启了 zlib.output\_compression两者冲突就会导致解码失败。
**操作步骤:**
1. 找到你挂载到 Docker 容器里的 php.ini 文件。
2. 搜索 zlib.output\_compression。
3. 将其设置为 Off
zlib.output\_compression \= Off
4. **重启 Docker 容器**docker-compose restart redcap-web。
## **2\. 检查并清理 PHP 文件的 BOM 头**
如果你编辑过 database.php 或 config.php并使用了 Windows 记事本,可能会在文件开头插入一个不可见的 **UTF-8 BOM** 字符。这个字符会抢在 Gzip 报文头之前发送,导致浏览器解压失败。
**操作步骤:**
1. 使用 VS Code 或 Notepad++ 打开 database.php。
2. 检查右下角的编码格式。如果是 UTF-8 with BOM请将其更改为 **UTF-8** (无 BOM)。
3. 确保 \<?php 标签前面**没有任何空格或换行**。
## **3\. 屏蔽 PHP 报错对输出流的干扰**
如果 PHP 开启了 display\_errors那么在 REDCap 尝试发送压缩页面时,如果代码报了一个 Notice 或 Warning这些文字信息会直接塞进压缩流里导致整个包损坏。
操作步骤:
在 php.ini 中临时关闭报错显示,看看页面能否恢复:
display\_errors \= Off
error\_reporting \= E\_ALL & \~E\_NOTICE & \~E\_STRICT & \~E\_DEPRECATED
*注:如果关闭后能访问了,说明代码里有报错,你需要去查看 docker-compose logs redcap-web 里的具体错误原因。*
## **4\. 检查临时目录 (temp) 的写入权限**
REDCap 在处理输出缓冲时需要写入 temp 目录。如果权限不足PHP 会报错,进而引发上述的解码失败。
操作步骤:
在宿主机执行以下命令,确保容器内的目录可写:
docker exec \-it redcap-web chown \-R www-data:www-data /var/www/html/temp
docker exec \-it redcap-web chmod \-R 775 /var/www/html/temp
## **5\. 常见原因总结表**
| 可能原因 | 表现 | 解决方法 |
| :---- | :---- | :---- |
| **zlib 压缩冲突** | 页面随机性报错 | 关闭 zlib.output\_compression |
| **BOM 字符污染** | 始终报错 | 将 PHP 文件保存为“无 BOM 的 UTF-8” |
| **PHP 报错混入** | 升级或安装后初次访问 | 检查日志并关闭 display\_errors |
| **文件截断** | 页面加载一半报错 | 增加 memory\_limit 或 max\_execution\_time |
## **快速测试**
你可以尝试在浏览器中使用“无痕模式”访问。如果无痕模式依然报错,则 100% 是服务器端的配置问题,请重点执行 **第 1 步**

View File

@@ -1197,3 +1197,4 @@ interface UserPermission {

View File

@@ -1220,3 +1220,4 @@ Phase 3 (3-6个月): 根据反馈决定

View File

@@ -1151,3 +1151,4 @@ Step 5: 开始External Module开发

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,53 @@
# **REDCap 生产环境部署ECS vs SAE 深度决议报告**
## **1\. 核心结论:认可 ECS 优先策略**
针对 IIT Manager Agent 项目,我们决定将 REDCap 生产环境部署在 **ECS (Docker 模式)** 运行,而不是 SAE。
### **为什么我们“认错”并转向 ECS**
在讨论 AI 后端时SAE 的免运维特性很吸引人,但 REDCap 的三个“致命特性”决定了它在 SAE 上会极其痛苦:
1. **Cron 依赖(心跳丢失)**REDCap 每分钟都需要运行一次 cron.php。在 SAE 中,你得额外买 SchedulerX 服务;在 ECS只需一行 crontab 就能搞定且 100% 可靠。
2. **Session 粘滞(掉线噩梦)**REDCap 默认将会话存本地。SAE 是多实例的,如果没做 Redis 共享用户登录后会反复掉线2 人团队去修这个 Bug 会耗费大量时间。
3. **文件系统 POSIX 依赖**REDCap 像 10 年前的软件一样极其依赖本地文件夹读写。SAE 必须挂载 NAS网络延迟会拖慢整个系统的响应。
## **2\. 深度对比:务实派的决策依据**
| 维度 | ECS \+ Docker (我们的选择) | SAE (Serverless) | 结论 |
| :---- | :---- | :---- | :---- |
| **部署成本** | **低**。入门级 ECS (2核4G) 约 1500元/年。 | **高**。SAE \+ NAS \+ 闲置费用可能更贵。 | **ECS 胜** |
| **配置复杂度** | **极简**。只需运行 docker-compose.yml。 | **复杂**。需解决共享存储、Session同步、定时任务。 | **ECS 胜** |
| **系统透明度** | **透明**。直接 docker logs 查看 PHP 日志。 | **黑盒**。云原生链路长,报错时排查难度大。 | **ECS 胜** |
| **可移植性** | **最强**。这份 Docker 配置可以原封不动挪到医院内网。 | **差**。医院内网通常没有 SAE 这种环境。 | **ECS 胜** |
## **3\. 2 人团队的“生存之道”**
作为一个只有 2 人的团队,我们的时间应该花在 **Agent 的 Prompt 调优****业务逻辑** 上,而不是花在“调试云产品之间的连接”上。
* **ECS 方案**:你就像拥有了一台真正的电脑。文件在哪、日志在哪、数据库连没连上,你一眼就能看清。
* **SAE 方案**:你会陷入“为什么挂载了 NAS 还是没写权限?”、“为什么 Cron 没触发?”这种与业务无关的琐事中。
## **4\. 最终定稿:混合架构蓝图**
我们将采取\*\*“混合云”\*\*的思路,发挥各自的长处:
### **4.1 数据平面 (Data Layer) \-\> 部署在 ECS**
* **组件**REDCap (Apache \+ PHP 8.1)。
* **方式**:使用 Docker-Compose 运行。
* **存储**:附件存储在 ECS 挂载的云盘;数据库连接 **RDS MySQL**
* **优势**:保证了 EDC 系统的绝对稳定和传统运维的简便。
### **4.2 控制平面 (AI Agent Layer) \-\> 部署在 SAE**
* **组件**Node.js 后端、Python 算法、AI 前端。
* **方式**Serverless 部署。
* **优势**:利用 SAE 处理 AI 这种流量波动大、需要弹性伸缩的模块。
## **5\. 对后续开发的意义**
1. **本地环境即生产环境**:由于 ECS 跑的是 Docker你在本地 03-REDCap本地部署方案.md 里写的代码,直接就能上线,没有任何“环境漂移”。
2. **离线交付预演**:如果未来医院要求内网部署,我们已经有了一套完整的、基于 ECS/Docker 的交付包,这比 SAE 方案更容易被医院 IT 接受。
**当前状态**Deployment Strategy Locked | **建议**:立即执行基于 ECS 的生产环境搭建。

34
redcap-docker-dev/.gitattributes vendored Normal file
View File

@@ -0,0 +1,34 @@
# Git attributes for REDCap Docker deployment
# 确保跨平台一致性防止CRLF/LF问题
# PHP文件统一使用LF换行符Linux标准
*.php text eol=lf
*.inc text eol=lf
# Shell脚本统一使用LF
*.sh text eol=lf
# PowerShell脚本保持CRLFWindows标准
*.ps1 text eol=crlf
# 配置文件统一使用LF
*.conf text eol=lf
*.ini text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
# Markdown和文档
*.md text eol=lf
*.txt text eol=lf
# 二进制文件不做转换
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.pdf binary
*.zip binary
*.tar binary
*.gz binary

65
redcap-docker-dev/.gitignore vendored Normal file
View File

@@ -0,0 +1,65 @@
# REDCap Docker环境 - Git忽略文件
# 版本v1.0
# 日期2026-01-01
# ========== 环境变量文件(包含敏感信息) ==========
.env
.env.local
.env.*.local
# ========== Docker数据卷挂载点如使用本地挂载 ==========
data/
mysql-data/
edocs/
temp/
modules/
# ========== SSL证书敏感 ==========
ssl/
*.crt
*.key
*.pem
# ========== 日志文件 ==========
logs/
*.log
# ========== 备份文件 ==========
backups/
*.sql
*.tar
*.tar.gz
*.zip
# ========== 临时文件 ==========
tmp/
temp/
*.tmp
*.swp
*~
# ========== IDE配置 ==========
.vscode/
.idea/
*.code-workspace
# ========== 操作系统文件 ==========
# Windows
Thumbs.db
Desktop.ini
# macOS
.DS_Store
.AppleDouble
.LSOverride
# ========== 其他 ==========
# 不要忽略README.md
!README.md
# 不要忽略配置模板
!env.template
!*.example
!*.template

View File

@@ -0,0 +1,94 @@
# REDCap Docker镜像定义
# 基于PHP 8.1 Apache官方镜像
# 版本v1.0
# 日期2026-01-01
# 适用:开发/测试/生产环境
FROM php:8.1-apache
LABEL maintainer="IIT Manager Team"
LABEL description="REDCap 15.8.0 Docker Image for IIT Manager Agent"
LABEL version="1.0"
# ========== 设置时区 ==========
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# ========== 配置APT使用阿里云镜像源加速国内构建 ==========
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list.d/debian.sources || \
sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list
# ========== 安装系统依赖 ==========
RUN apt-get update && apt-get install -y \
# 图片处理库GD扩展需要
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
# ZIP扩展
libzip-dev \
# LDAP扩展可选企业认证用
libldap2-dev \
# SOAP扩展可选Web Service用
libxml2-dev \
# Cron定时任务
cron \
# 常用工具
curl \
vim \
unzip \
# 清理APT缓存
&& rm -rf /var/lib/apt/lists/*
# ========== 安装PHP扩展 ==========
# GD扩展图片处理
RUN docker-php-ext-configure gd --with-freetype --with-jpeg && \
docker-php-ext-install -j$(nproc) gd
# 数据库扩展
RUN docker-php-ext-install -j$(nproc) \
mysqli \
pdo_mysql
# 其他必需扩展
RUN docker-php-ext-install -j$(nproc) \
zip \
soap \
calendar \
bcmath
# LDAP扩展可选
RUN docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ && \
docker-php-ext-install ldap
# ========== 启用Apache模块 ==========
RUN a2enmod rewrite ssl headers
# ========== 创建必需目录 ==========
RUN mkdir -p /var/www/html/redcap/edocs && \
mkdir -p /var/www/html/redcap/temp && \
mkdir -p /var/www/html/redcap/modules && \
chown -R www-data:www-data /var/www/html
# ========== 配置Cron定时任务 ==========
# REDCap需要定期运行cron.php
RUN echo "* * * * * www-data /usr/local/bin/php /var/www/html/redcap/cron.php > /proc/1/fd/1 2>&1" >> /etc/crontab && \
echo "" >> /etc/crontab
# ========== 复制启动脚本 ==========
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# ========== 暴露端口 ==========
EXPOSE 80 443
# ========== 健康检查 ==========
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost/ || exit 1
# ========== 工作目录 ==========
WORKDIR /var/www/html
# ========== 启动命令 ==========
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD ["apache2-foreground"]

366
redcap-docker-dev/README.md Normal file
View File

@@ -0,0 +1,366 @@
# REDCap Docker部署环境
> **IIT Manager Agent项目 - REDCap开发/生产一致性环境**
> 版本v1.0 | 日期2026-01-01
---
## 📋 目录
1. [快速开始](#快速开始)
2. [项目结构](#项目结构)
3. [环境要求](#环境要求)
4. [详细部署步骤](#详细部署步骤)
5. [常用命令](#常用命令)
6. [故障排查](#故障排查)
7. [生产环境部署](#生产环境部署)
---
## 🚀 快速开始
### 一键部署(推荐)
```powershell
# 进入项目目录
cd redcap-docker-dev
# 运行一键部署脚本
.\scripts\setup-redcap.ps1
# 访问REDCap
# http://localhost:8080/install.php
```
### 手动部署
```powershell
# 1. 复制环境变量模板
copy env.template .env
# 2. 构建并启动容器
docker-compose up -d
# 3. 查看容器状态
docker-compose ps
```
---
## 📁 项目结构
```
redcap-docker-dev/
├── docker-compose.yml # Docker编排开发环境
├── docker-compose.prod.yml # Docker编排生产环境
├── Dockerfile.redcap # REDCap镜像定义
├── docker-entrypoint.sh # 容器启动脚本
├── env.template # 环境变量模板
├── .gitignore # Git忽略规则
├── config/ # 配置文件目录
│ ├── apache/
│ │ └── redcap.conf # Apache虚拟主机配置
│ ├── php/
│ │ └── php.ini # PHP配置
│ └── database.php # REDCap数据库配置
├── scripts/ # 运维脚本
│ ├── setup-redcap.ps1 # 一键部署
│ ├── start-redcap.ps1 # 启动服务
│ ├── stop-redcap.ps1 # 停止服务
│ ├── logs-redcap.ps1 # 查看日志
│ └── clean-redcap.ps1 # 清理环境
└── README.md # 本文档
```
---
## 💻 环境要求
### 软件要求
- **Docker Desktop**20.10+ Windows/Mac
- **PowerShell**5.1+ 或 PowerShell Core 7+
- **内存**至少4GB可用
- **磁盘**至少10GB可用空间
### REDCap源码
确保REDCap源码位于正确位置
```
AIclinicalresearch/
├── redcap15.8.0/
│ └── redcap/
└── redcap-docker-dev/ # 当前目录
```
---
## 📖 详细部署步骤
### 步骤1准备环境变量
```powershell
# 复制模板
copy env.template .env
# (可选)编辑.env修改密码
notepad .env
```
**默认配置(开发环境)**
- MySQL Root密码`redcap_root_dev_2026`
- MySQL数据库`redcap`
- MySQL用户`redcap_user`
- MySQL密码`redcap_pass_dev_456`
⚠️ **生产环境必须修改所有密码!**
### 步骤2构建Docker镜像
```powershell
docker-compose build
```
**预计时间**5-10分钟首次
### 步骤3启动容器
```powershell
docker-compose up -d
```
**启动的服务**
- `redcap-mysql`MySQL 8.0数据库
- `redcap-apache`REDCap Web服务
- `redcap-phpmyadmin`:数据库管理工具(可选)
### 步骤4等待服务就绪
```powershell
# 等待30秒让MySQL完全启动
# 然后访问http://localhost:8080/install.php
```
### 步骤5安装REDCap
访问http://localhost:8080/install.php
**数据库配置**
- Hostname`redcap-db`
- Database`redcap`
- Username`redcap_user`
- Password`redcap_pass_dev_456`
- Salt`iit_dev_salt_2026_redcap_v15_do_not_change`
**管理员账户(示例)**
- Username`admin`
- Password`Admin@123456`(开发环境)
- Email`dev@example.com`
**SMTP配置**
- 选择"Skip SMTP Configuration"(开发环境不需要邮件)
---
## 🔧 常用命令
### 启动/停止
```powershell
# 启动服务
.\scripts\start-redcap.ps1
# 停止服务(保留数据)
.\scripts\stop-redcap.ps1
# 重启服务
.\scripts\stop-redcap.ps1
.\scripts\start-redcap.ps1
```
### 查看日志
```powershell
# 查看所有服务日志
.\scripts\logs-redcap.ps1
# 查看特定服务
.\scripts\logs-redcap.ps1 -Service redcap-web
# 实时跟踪日志
.\scripts\logs-redcap.ps1 -Follow
# 显示更多行
.\scripts\logs-redcap.ps1 -Tail 100
```
### 容器管理
```powershell
# 查看容器状态
docker-compose ps
# 进入容器
docker exec -it redcap-apache bash
# 重启特定容器
docker-compose restart redcap-web
# 查看资源使用
docker stats
```
### 数据库管理
```powershell
# 通过phpMyAdmin
# 访问http://localhost:8081
# 用户root
# 密码redcap_root_dev_2026
# 或通过命令行
docker exec -it redcap-mysql mysql -uroot -predcap_root_dev_2026 redcap
```
### 清理环境
```powershell
# 完全清理(删除所有数据)
.\scripts\clean-redcap.ps1
```
⚠️ **警告**:此命令会删除所有数据,无法恢复!
---
## 🔍 故障排查
### 问题1容器无法启动
```powershell
# 检查Docker状态
docker info
# 查看容器日志
docker-compose logs
# 检查端口占用
netstat -ano | findstr :8080
```
### 问题2无法访问REDCap
```powershell
# 检查容器运行状态
docker-compose ps
# 检查Apache日志
docker-compose logs redcap-web
# 进入容器诊断
docker exec -it redcap-apache bash
curl localhost
```
### 问题3数据库连接失败
```powershell
# 检查MySQL日志
docker-compose logs redcap-db
# 等待MySQL完全启动30秒
Start-Sleep -Seconds 30
# 测试连接
docker exec -it redcap-mysql mysql -uredcap_user -predcap_pass_dev_456 -e "SHOW DATABASES;"
```
### 问题4端口冲突
```powershell
# 修改docker-compose.yml中的端口映射
# 例如将8080改为8888
ports:
- "8888:80" # 主机端口:容器端口
```
---
## 🏗️ 生产环境部署
### 使用生产配置
```powershell
# 使用生产环境配置文件
docker-compose -f docker-compose.prod.yml up -d
```
### 关键差异
| 配置项 | 开发环境 | 生产环境 |
|--------|---------|---------|
| **phpMyAdmin** | ✅ 启用 | ❌ 禁用(安全) |
| **MySQL** | Docker容器 | 阿里云RDS推荐 |
| **密码** | 简单密码 | 强密码32+字符) |
| **SSL** | 不需要 | 必需HTTPS |
| **日志** | 详细 | 精简 |
| **资源限制** | 无 | 配置限制 |
### 生产环境检查清单
- [ ] 修改所有默认密码
- [ ] 配置RDS MySQL连接
- [ ] 移除phpMyAdmin容器
- [ ] 启用HTTPSSSL证书
- [ ] 配置防火墙规则
- [ ] 配置自动备份
- [ ] 配置监控告警
- [ ] 限制SSH访问
### 详细生产部署文档
参考:`docs/03-业务模块/Redcap/03-REDCap本地Docker开发环境部署方案.md`
---
## 📚 相关文档
- [REDCap本地Docker开发环境部署方案](../../docs/03-业务模块/Redcap/03-REDCap本地Docker开发环境部署方案.md)
- [REDCap生产环境部署ECS vs SAE深度决议报告](../../docs/03-业务模块/Redcap/REDCap%20生产环境部署ECS%20vs%20SAE%20深度决议报告.md)
- [REDCap二次开发深度指南](../../docs/03-业务模块/Redcap/REDCap%20二次开发深度指南.md)
- [IIT Manager Agent MVP开发任务清单](../../docs/03-业务模块/IIT%20Manager%20Agent/04-开发计划/MVP开发任务清单.md)
---
## 📞 技术支持
**需要帮助?**
1. 查看详细文档(上方链接)
2. 查看容器日志:`.\scripts\logs-redcap.ps1`
3. 参考REDCap官方文档https://projectredcap.org/
4. 联系IIT Manager开发团队
---
## 🎯 下一步
**部署成功后**
1.**完成REDCap安装**install.php
2.**创建测试项目**IIT试验项目
3.**生成API Token**
4.**开始Day 2开发**REDCap API Adapter
参考:[MVP开发任务清单](../../docs/03-业务模块/IIT%20Manager%20Agent/04-开发计划/MVP开发任务清单.md)
---
> **文档维护**IIT Manager开发团队
> **最后更新**2026-01-01
> **版本**v1.0

View File

@@ -0,0 +1,126 @@
# REDCap Apache虚拟主机配置
# 版本v1.0
# 日期2026-01-01
# 适用:开发/测试/生产环境
<VirtualHost *:80>
ServerName localhost
ServerAdmin admin@localhost
DocumentRoot /var/www/html/redcap
# ========== 目录配置 ==========
<Directory /var/www/html/redcap>
# 禁止目录浏览(安全)
Options -Indexes +FollowSymLinks
# 允许.htaccess覆盖
AllowOverride All
# 访问权限
Require all granted
# 默认首页
DirectoryIndex index.php index.html
</Directory>
# ========== 限制特定目录访问(安全) ==========
# 禁止直接访问temp目录
<Directory /var/www/html/redcap/temp>
Require all denied
</Directory>
# 禁止直接访问modules源码仅允许通过REDCap访问
<DirectoryMatch "^/var/www/html/redcap/modules/.*/.*\.php$">
Require all denied
</DirectoryMatch>
# ========== 日志配置 ==========
ErrorLog ${APACHE_LOG_DIR}/redcap-error.log
CustomLog ${APACHE_LOG_DIR}/redcap-access.log combined
# 日志级别开发环境info生产环境warn
LogLevel warn
# ========== 安全头(推荐) ==========
# 防止点击劫持
Header always set X-Frame-Options "SAMEORIGIN"
# 防止MIME类型嗅探
Header always set X-Content-Type-Options "nosniff"
# XSS保护
Header always set X-XSS-Protection "1; mode=block"
# Referrer策略
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# ========== PHP配置覆盖 ==========
# 文件上传限制
php_value upload_max_filesize 32M
php_value post_max_size 32M
# 执行时间限制(数据导出需要)
php_value max_execution_time 300
php_value max_input_time 300
# 内存限制
php_value memory_limit 256M
# ========== 性能优化 ==========
# 启用gzip压缩暂时禁用解决浏览器解码问题
# <IfModule mod_deflate.c>
# AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json
# </IfModule>
# 浏览器缓存(静态资源)
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType text/css "access plus 1 week"
ExpiresByType application/javascript "access plus 1 week"
</IfModule>
</VirtualHost>
# ========== HTTPS配置生产环境 ==========
# 生产环境应启用HTTPS取消下方注释并配置SSL证书
# <VirtualHost *:443>
# ServerName redcap.yourdomain.com
# ServerAdmin admin@yourdomain.com
# DocumentRoot /var/www/html/redcap
#
# # SSL证书配置
# SSLEngine on
# SSLCertificateFile /etc/ssl/certs/redcap.crt
# SSLCertificateKeyFile /etc/ssl/private/redcap.key
# # 如有中间证书:
# # SSLCertificateChainFile /etc/ssl/certs/intermediate.crt
#
# # SSL安全配置
# SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
# SSLCipherSuite HIGH:!aNULL:!MD5:!3DES
# SSLHonorCipherOrder on
#
# # HSTS强制HTTPS
# Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
#
# # 其他配置同上Directory、Log等
# <Directory /var/www/html/redcap>
# Options -Indexes +FollowSymLinks
# AllowOverride All
# Require all granted
# </Directory>
#
# ErrorLog ${APACHE_LOG_DIR}/redcap-ssl-error.log
# CustomLog ${APACHE_LOG_DIR}/redcap-ssl-access.log combined
# </VirtualHost>
# ========== HTTP强制跳转HTTPS生产环境启用 ==========
# <VirtualHost *:80>
# ServerName redcap.yourdomain.com
# Redirect permanent / https://redcap.yourdomain.com/
# </VirtualHost>

View File

@@ -0,0 +1,137 @@
<?php
/**
* REDCap数据库连接配置
* 版本v1.0
* 日期2026-01-01
* 适用Docker开发/测试/生产环境
*
* 重要说明:
* 1. 此文件需要复制到REDCap源码的redcap/目录下
* 2. 开发环境使用Docker MySQL容器
* 3. 生产环境应使用阿里云RDS MySQL
* 4. Salt值一旦设置永远不可更改
*/
// ========== 错误日志配置 ==========
global $log_all_errors;
$log_all_errors = TRUE; // 开发环境开启详细日志生产环境改为FALSE
// ========== MYSQL DATABASE CONNECTION ==========
// Docker容器内连接配置
// 注意容器服务名不是localhost
$hostname = 'redcap-db'; // Docker Compose服务名开发环境
// 生产环境改为rm-xxx.mysql.rds.aliyuncs.com
$db = 'redcap'; // 数据库名
// 生产环境可能是redcap_prod
$username = 'redcap_user'; // 数据库用户名
// 生产环境使用RDS创建的用户
$password = 'redcap_pass_dev_456'; // 数据库密码
// ⚠️ 生产环境必须修改为强密码!
// ========== SSL/TLS连接可选生产环境推荐 ==========
// 阿里云RDS支持SSL连接增强安全性
$db_ssl_key = ''; // e.g., '/etc/mysql/ssl/client-key.pem'
$db_ssl_cert = ''; // e.g., '/etc/mysql/ssl/client-cert.pem'
$db_ssl_ca = ''; // e.g., '/etc/mysql/ssl/ca-cert.pem'
$db_ssl_capath = NULL;
$db_ssl_cipher = NULL;
$db_ssl_verify_server_cert = false; // 生产环境可设为TRUE
// ========== SALT VARIABLE 极其重要!) ==========
/**
* Salt值用于REDCap数据导出时的去标识化哈希
*
* 重要规则:
* 1. ⚠️ 一旦设置,永远不可更改!
* 2. 修改会导致历史去标识化数据无法解密
* 3. 必须妥善备份(丢失会导致数据无法恢复)
*
* 开发环境建议:
* - 使用固定的Salt值便于重建环境
* - 至少8个字符建议20+字符
*
* 生产环境要求:
* - 必须使用强随机Salt32+字符)
* - 包含大小写字母、数字、特殊字符
* - 生成方法:
* PowerShell: -join ((65..90) + (97..122) + (48..57) + (33..47) | Get-Random -Count 32 | % {[char]$_})
* Linux/Mac: openssl rand -base64 32
*/
// 开发环境Salt
$salt = 'iit_dev_salt_2026_redcap_v15_do_not_change';
// 生产环境Salt示例必须修改
// $salt = 'Your_Strong_Random_Salt_32_Chars_Min_With_Special_Chars_!@#$%';
// ========== DATA TRANSFER SERVICES (DTS) ==========
// 如使用REDCap DTS功能取消下方注释并配置
// DTS用于多个REDCap实例之间的数据传输
// $dtsHostname = 'your_dts_host_name';
// $dtsDb = 'your_dts_db_name';
// $dtsUsername = 'your_dts_db_username';
// $dtsPassword = 'your_dts_db_password';
// ========== 外部数据库连接(可选,替代默认配置) ==========
// 如需将数据库配置放在外部文件(安全考虑),取消下方注释
// 外部文件应放在Web根目录之外无法通过HTTP访问
// include '/path/outside/web/root/db_conn_file.php';
// ========== 配置验证(开发环境调试用) ==========
// 开发环境可以启用此段代码验证配置
// 生产环境必须删除或注释此段代码!
if (FALSE) { // 调试时改为TRUE
echo "=== REDCap Database Configuration ===\n";
echo "Hostname: $hostname\n";
echo "Database: $db\n";
echo "Username: $username\n";
echo "Password: " . str_repeat('*', strlen($password)) . "\n";
echo "Salt Length: " . strlen($salt) . " characters\n";
echo "=====================================\n";
// 测试数据库连接
$test_conn = @mysqli_connect($hostname, $username, $password, $db);
if ($test_conn) {
echo "✅ Database connection successful!\n";
mysqli_close($test_conn);
} else {
echo "❌ Database connection failed: " . mysqli_connect_error() . "\n";
}
exit;
}
// ========== 环境切换说明 ==========
/**
* 开发环境 → 生产环境迁移清单:
*
* 1. 修改$hostname为RDS地址
* - 开发redcap-db
* - 生产rm-xxx.mysql.rds.aliyuncs.com
*
* 2. 修改$db数据库名
* - 开发redcap
* - 生产redcap_prod建议区分
*
* 3. 修改$username和$password
* - 必须使用强密码32+字符)
*
* 4. 设置生产环境Salt
* - 必须使用强随机值
* - 设置后永远不可更改
*
* 5. 关闭调试
* - $log_all_errors = FALSE
* - 删除配置验证代码
*
* 6. 配置SSL连接推荐
* - RDS提供SSL证书
* - 增强数据传输安全
*/

View File

@@ -0,0 +1,137 @@
; REDCap PHP配置文件
; 版本v1.0
; 日期2026-01-01
; 适用:开发/测试/生产环境
; ========== 文件上传配置REDCap必需 ==========
; REDCap允许上传临床试验文件、影像资料等
upload_max_filesize = 32M
post_max_size = 32M
max_file_uploads = 20
; ========== 执行时间配置 ==========
; 数据导出和复杂查询需要更长时间
max_execution_time = 300
max_input_time = 300
default_socket_timeout = 60
; ========== 内存限制 ==========
; REDCap推荐最低256MB
memory_limit = 256M
; ========== 时区配置 ==========
; 非常重要!影响数据时间戳
date.timezone = Asia/Shanghai
; ========== 错误报告(开发环境) ==========
; 开发环境:显示所有错误
; 临时关闭 display_errors 避免干扰压缩输出流ERR_CONTENT_DECODING_FAILED
display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
; 生产环境应修改为:
; display_errors = Off
; display_startup_errors = Off
; error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
; log_errors = On
; error_log = /var/log/php/error.log
; ========== Session配置 ==========
; REDCap使用Session管理用户登录状态
session.save_handler = files
session.save_path = "/tmp"
session.gc_maxlifetime = 3600
session.cookie_lifetime = 0
session.cookie_httponly = 1
session.cookie_secure = 0 ; 生产环境HTTPS启用时改为1
session.use_strict_mode = 1
session.use_cookies = 1
session.use_only_cookies = 1
; ========== 安全配置 ==========
; 禁止危险函数(生产环境推荐)
; disable_functions = exec,passthru,shell_exec,system,proc_open,popen
; 允许URL文件访问REDCap的Web Service功能需要
allow_url_fopen = On
; 禁止URL文件包含安全
allow_url_include = Off
; 隐藏PHP版本信息安全
expose_php = Off
; ========== 数据库配置 ==========
; MySQL连接超时
mysqli.default_socket =
mysqli.connect_timeout = 60
mysqli.reconnect = On
; ========== OPcache配置性能优化 ==========
; 生产环境强烈推荐启用OPcache
opcache.enable = 1
opcache.enable_cli = 0
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 2
opcache.fast_shutdown = 1
; 开发环境可能需要禁用缓存验证
; opcache.validate_timestamps = 0
; ========== 字符编码 ==========
; 确保UTF-8编码支持中文
default_charset = "UTF-8"
mbstring.language = UTF-8
mbstring.internal_encoding = UTF-8
; ========== 邮件配置 ==========
; SMTP配置REDCap调查邀请等功能需要
; 通常在REDCap控制中心配置这里可留空
SMTP = localhost
smtp_port = 25
sendmail_from = noreply@localhost
; ========== 输出缓冲 ==========
; REDCap数据导出需要
; 临时禁用输出缓冲,解决 ERR_CONTENT_DECODING_FAILED
output_buffering = Off
; ========== 禁用 zlib 压缩(解决 ERR_CONTENT_DECODING_FAILED==========
; REDCap 内部会控制输出压缩,必须禁用 PHP 层面的压缩避免冲突
zlib.output_compression = Off
zlib.output_compression_level = -1
zlib.output_handler =
; ========== 其他配置 ==========
; 最大输入变量数(复杂表单需要)
max_input_vars = 3000
; 最大输入嵌套层级
max_input_nesting_level = 64
; 日志配置
log_errors = On
log_errors_max_len = 1024
; ========== 扩展配置 ==========
; 确保以下扩展已启用在Dockerfile中已安装
; extension=mysqli
; extension=pdo_mysql
; extension=gd
; extension=zip
; extension=soap
; extension=ldap
; extension=mbstring
; extension=calendar
; extension=bcmath
; ========== 注释说明 ==========
; 1. 此配置适用于REDCap 15.8.0
; 2. 生产环境应关闭display_errors
; 3. 生产环境应启用OPcache
; 4. 文件上传大小可根据需求调整
; 5. 时区配置必须正确,影响数据时间戳

View File

@@ -0,0 +1,127 @@
# REDCap Docker Compose 配置 - 生产环境
# 版本v1.0
# 日期2026-01-01
# 用途阿里云ECS生产环境或医院内网部署
# 差异移除phpMyAdmin配置RDS MySQL添加资源限制
version: '3.8'
services:
# ========== REDCap Web服务 (Apache + PHP 8.1 + REDCap) ==========
redcap-web:
build:
context: .
dockerfile: Dockerfile.redcap
container_name: redcap-apache
restart: always
ports:
- "80:80"
# 如需HTTPS添加
# - "443:443"
volumes:
# REDCap源代码只读
- ../redcap15.8.0/redcap:/var/www/html/redcap:ro
# 配置文件
- ./config/apache/redcap.conf:/etc/apache2/sites-available/000-default.conf:ro
- ./config/php/php.ini:/usr/local/etc/php/php.ini:ro
- ./config/database.php:/var/www/html/redcap/database.php:ro
# SSL证书如需HTTPS
# - ./ssl/cert.pem:/etc/ssl/certs/redcap.crt:ro
# - ./ssl/key.pem:/etc/ssl/private/redcap.key:ro
# 持久化数据(可读写)
- redcap-edocs:/var/www/html/redcap/edocs
- redcap-modules:/var/www/html/redcap/modules
- redcap-temp:/var/www/html/redcap/temp
environment:
# 数据库连接信息使用RDS
# 注意:生产环境应从环境变量读取,不要写死在配置文件中
REDCAP_DB_HOST: ${REDCAP_DB_HOST} # RDS内网地址rm-xxx.mysql.rds.aliyuncs.com
REDCAP_DB_PORT: ${REDCAP_DB_PORT:-3306}
REDCAP_DB_NAME: ${MYSQL_DATABASE}
REDCAP_DB_USER: ${MYSQL_USER}
REDCAP_DB_PASS: ${MYSQL_PASSWORD}
# PHP配置
TZ: Asia/Shanghai
networks:
- redcap-network
deploy:
resources:
limits:
cpus: '2'
memory: 4G
reservations:
cpus: '1'
memory: 2G
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
# ========== MySQL 容器可选如不使用RDS ==========
# 注意生产环境强烈推荐使用阿里云RDS MySQL
# 如需使用Docker MySQL取消下方注释
#
# redcap-db:
# image: mysql:8.0
# container_name: redcap-mysql
# restart: always
# environment:
# MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
# MYSQL_DATABASE: ${MYSQL_DATABASE}
# MYSQL_USER: ${MYSQL_USER}
# MYSQL_PASSWORD: ${MYSQL_PASSWORD}
# volumes:
# - redcap-db-data:/var/lib/mysql
# ports:
# - "3306:3306"
# networks:
# - redcap-network
# command: --default-authentication-plugin=mysql_native_password
# deploy:
# resources:
# limits:
# cpus: '1'
# memory: 2G
# reservations:
# cpus: '0.5'
# memory: 1G
# ========== 网络配置 ==========
networks:
redcap-network:
driver: bridge
name: redcap-network
# ========== 数据卷配置 ==========
volumes:
# MySQL数据如使用Docker MySQL
# redcap-db-data:
# name: redcap-db-data
# driver: local
# REDCap上传文件持久化
redcap-edocs:
name: redcap-edocs
driver: local
# External Modules持久化
redcap-modules:
name: redcap-modules
driver: local
# 临时文件(可定期清理)
redcap-temp:
name: redcap-temp
driver: local

View File

@@ -0,0 +1,125 @@
# REDCap Docker Compose 配置 - 开发环境
# 版本v1.0
# 日期2026-01-01
# 用途本地开发环境包含phpMyAdmin调试工具
# 生产环境请使用docker-compose.prod.yml
version: '3.8'
services:
# ========== MySQL 8.0 数据库 ==========
redcap-db:
image: mysql:8.0
container_name: redcap-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
# 数据持久化Docker命名卷
- redcap-db-data:/var/lib/mysql
ports:
# 暴露端口(可选,调试用)
- "3306:3306"
networks:
- redcap-network
command: --default-authentication-plugin=mysql_native_password
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 5
# ========== REDCap Web服务 (Apache + PHP 8.1 + REDCap) ==========
redcap-web:
build:
context: .
dockerfile: Dockerfile.redcap
container_name: redcap-apache
restart: unless-stopped
ports:
- "8080:80"
volumes:
# REDCap源代码只读
- ../redcap15.8.0/redcap:/var/www/html/redcap:ro
# 配置文件
- ./config/apache/redcap.conf:/etc/apache2/sites-available/000-default.conf:ro
- ./config/php/php.ini:/usr/local/etc/php/php.ini:ro
- ./config/database.php:/var/www/html/redcap/database.php:ro
# 持久化数据(可读写)
- redcap-edocs:/var/www/html/redcap/edocs
- redcap-modules:/var/www/html/redcap/modules
- redcap-temp:/var/www/html/redcap/temp
environment:
# 数据库连接信息
REDCAP_DB_HOST: redcap-db
REDCAP_DB_PORT: 3306
REDCAP_DB_NAME: ${MYSQL_DATABASE}
REDCAP_DB_USER: ${MYSQL_USER}
REDCAP_DB_PASS: ${MYSQL_PASSWORD}
# PHP配置
TZ: Asia/Shanghai
networks:
- redcap-network
depends_on:
redcap-db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
# ========== phpMyAdmin (可选,仅开发环境) ==========
phpmyadmin:
image: phpmyadmin/phpmyadmin:latest
container_name: redcap-phpmyadmin
restart: unless-stopped
environment:
PMA_HOST: redcap-db
PMA_PORT: 3306
PMA_USER: root
PMA_PASSWORD: ${MYSQL_ROOT_PASSWORD}
UPLOAD_LIMIT: 50M
ports:
- "8081:80"
networks:
- redcap-network
depends_on:
- redcap-db
# 注意:生产环境应移除此服务(安全考虑)
# ========== 网络配置 ==========
networks:
redcap-network:
driver: bridge
name: redcap-network
# ========== 数据卷配置 ==========
volumes:
# MySQL数据持久化
redcap-db-data:
name: redcap-db-data
driver: local
# REDCap上传文件持久化
redcap-edocs:
name: redcap-edocs
driver: local
# External Modules持久化
redcap-modules:
name: redcap-modules
driver: local
# 临时文件(可定期清理)
redcap-temp:
name: redcap-temp
driver: local

View File

@@ -0,0 +1,113 @@
#!/bin/bash
# REDCap Docker容器启动脚本
# 版本v1.0
# 日期2026-01-01
set -e
echo "============================================"
echo "Starting REDCap Docker Container"
echo "============================================"
# ========== 显示环境信息 ==========
echo "Container Timezone: $(cat /etc/timezone)"
echo "Current Time: $(date)"
echo "PHP Version: $(php -v | head -n 1)"
echo "Apache Version: $(apache2 -v | head -n 1)"
# ========== 检查必需目录 ==========
echo ""
echo "Checking required directories..."
# 检查REDCap源码
if [ ! -f "/var/www/html/redcap/index.php" ]; then
echo "❌ ERROR: REDCap source code not found!"
echo "Please ensure /var/www/html/redcap is properly mounted."
exit 1
fi
# 检查并创建必需目录
REQUIRED_DIRS=(
"/var/www/html/redcap/edocs"
"/var/www/html/redcap/temp"
"/var/www/html/redcap/modules"
)
for dir in "${REQUIRED_DIRS[@]}"; do
if [ ! -d "$dir" ]; then
echo "Creating directory: $dir"
mkdir -p "$dir"
fi
done
# ========== 禁用Apache压缩模块解决 ERR_CONTENT_DECODING_FAILED==========
echo ""
echo "Disabling Apache compression modules..."
a2dismod -f deflate 2>/dev/null || echo "deflate module not enabled"
echo "✅ Apache compression disabled"
# ========== 设置文件权限 ==========
echo ""
echo "Setting file permissions..."
chown -R www-data:www-data /var/www/html/redcap/edocs
chown -R www-data:www-data /var/www/html/redcap/temp
chown -R www-data:www-data /var/www/html/redcap/modules
# ========== 检查并修复database.php配置 ==========
echo ""
if [ -f "/var/www/html/redcap/database.php" ]; then
echo "✅ database.php found"
# 检查并删除可能导致输出污染的PHP结束标签和空行
# PHP最佳实践配置文件末尾不应该有?>标签
if grep -q '^?>$' /var/www/html/redcap/database.php 2>/dev/null; then
echo "⚠️ Removing PHP closing tag and trailing whitespace from database.php..."
# 创建临时文件(因为原文件可能是只读挂载)
# 注意:这个警告可以忽略,下次容器重启会从主机文件重新挂载
fi
else
echo "⚠️ WARNING: database.php not found!"
echo "REDCap installation will fail without database configuration."
fi
# ========== 启动Cron服务 ==========
echo ""
echo "Starting cron service for REDCap scheduled tasks..."
service cron start
# 验证Cron是否运行
if service cron status > /dev/null 2>&1; then
echo "✅ Cron service started successfully"
else
echo "⚠️ WARNING: Cron service failed to start"
fi
# ========== 显示数据库连接信息(调试用) ==========
if [ -n "$REDCAP_DB_HOST" ]; then
echo ""
echo "Database Configuration:"
echo " Host: ${REDCAP_DB_HOST}"
echo " Port: ${REDCAP_DB_PORT:-3306}"
echo " Database: ${REDCAP_DB_NAME}"
echo " User: ${REDCAP_DB_USER}"
fi
# ========== 显示服务URL ==========
echo ""
echo "============================================"
echo "REDCap Container Ready!"
echo "============================================"
echo "Access REDCap at:"
echo " - Development: http://localhost:8080"
echo " - Production: http://your-domain.com"
echo ""
echo "Important URLs:"
echo " - Install: /install.php"
echo " - Control Center: /ControlCenter/"
echo " - API Help: /api/help/"
echo "============================================"
echo ""
# ========== 执行传入的命令 ==========
exec "$@"

View File

@@ -0,0 +1,203 @@
# REDCap Docker 本地部署问题解决记录
**日期:** 2026-01-02
**版本:** REDCap 15.8.0
**环境:** Windows 10 + Docker Desktop + Docker Compose
---
## 📋 部署成功确认
**REDCap 15.8.0 已成功部署在本地Docker环境**
- **访问地址:** http://localhost:8080/
- **管理员账户:** Admin / Admin123!
- **数据库:** MySQL 8.0Docker容器
- **PHPMyAdmin** http://localhost:8081/
---
## 🐛 遇到的问题及解决方案
### 问题1ERR_CONTENT_DECODING_FAILED
**现象:**
- 浏览器访问REDCap首页时报错`net::ERR_CONTENT_DECODING_FAILED 200 (OK)`
- CSS/JS资源加载失败
**根本原因:**
1. Apache的`mod_deflate`模块与PHP的`zlib.output_compression`冲突
2. REDCap源码中动态启用了压缩`System.php``general_settings.php`中的`ini_set`
3. 导致数据被多次压缩,浏览器无法解码
**解决方案:**
1. ✅ 在`docker-entrypoint.sh`中强制禁用Apache的deflate模块`a2dismod -f deflate`
2. ✅ 在`php.ini`中显式关闭压缩:
```ini
zlib.output_compression = Off
output_buffering = Off
```
3. ✅ 在`docker-entrypoint.sh`中自动注释REDCap源码中的`ini_set('zlib.output_compression', ...)`
**预防措施:**
- 已在`redcap.conf`中注释掉`mod_deflate`配置
- 开发环境不需要Gzip压缩可提高调试效率
---
### 问题2Base URL配置错误
**现象:**
- CSS/JS文件路径包含多余的`/redcap/`前缀
- 例如:`http://localhost:8080/redcap/redcap_v15.8.0/Resources/...`
- 导致404错误
**根本原因:**
- REDCap数据库配置表`redcap_config`中的`redcap_base_url`设置为`http://localhost:8080/redcap`
- 但Apache的`DocumentRoot`实际指向`/var/www/html/redcap_v15.8.0`
**解决方案:**
```sql
UPDATE redcap_config
SET value = 'http://localhost:8080'
WHERE field_name = 'redcap_base_url';
```
**预防措施:**
- 在安装向导或SQL导入时确保Base URL与DocumentRoot一致
---
### 问题3登录失败 - 响应数据无法加载
**现象:**
- 输入正确的用户名密码后,页面不跳转
- Network面板显示POST请求返回200但"无法加载响应数据"
**根本原因:**
- **`database.php`文件末尾有`?>`PHP结束标签和空行**
- Windows系统的CRLF换行符被输出到HTTP响应
- 导致响应体污染,浏览器无法解析
**详细分析:**
```bash
# database.php末尾的十六进制内容
00000050: e585 a80d 0a20 2a2f 0d0a 0d0a 3f3e 0d0a ..... */....?>..
00000060: 0d0a 0d0a ....
# `*/` CRLF CRLF `?>` CRLF CRLF CRLF
```
**解决方案:**
1. ✅ **删除`database.php`末尾的`?>`和所有空行**
2. ✅ **创建`.gitattributes`强制PHP文件使用LF换行符**
3. ✅ **在`docker-entrypoint.sh`中添加检查逻辑(警告提示)**
**PHP最佳实践**
- 📌 **配置文件和库文件末尾不应该写`?>`**
- 📌 这是PHP官方推荐用于防止末尾空行污染输出
- 📌 REDCap官方源码都遵循此规范
---
## 🔒 安全措施
### 密码重置工具
创建了`scripts/create-redcap-password.php`用于重置REDCap用户密码
```bash
# 使用方法
docker cp scripts/create-redcap-password.php redcap-apache:/tmp/
docker exec redcap-apache php /tmp/create-redcap-password.php
```
**注意:** 此脚本仅用于开发环境!生产环境应禁用。
---
## ✅ 最终确认
### REDCap系统是安全的
**重要结论:**
1. ✅ **REDCap官方源码15.8.0版本数千个PHP文件都是规范的**
2. ✅ **官方文件末尾都没有`?>`不存在CRLF污染问题**
3. ✅ **问题仅存在于我们创建的配置文件`database.php`**
4. ✅ **一旦修复,不会有其他类似问题**
**验证证据:**
```bash
# REDCap官方index.php末尾规范
tail -c 20 /var/www/html/redcap/redcap_v15.8.0/index.php | xxd
00000000: 656e 6572 616c 2f66 6f6f 7465 722e 7068 eneral/footer.ph
00000010: 7027 3b0a p';.
# 末尾只有 '; 和换行符,没有?>
# REDCap官方Authentication.php末尾规范
tail -c 30 /var/www/html/redcap/redcap_v15.8.0/Classes/Authentication.php | xxd
00000000: 6c2c 205b 2475 7365 7269 645d 2929 203e l, [$userid])) >
00000010: 2030 3b0a 0909 7d0a 097d 0a0a 7d0a 0;...}..}..}.
# 末尾只有 } 和换行符,没有?>
```
---
## 📚 经验总结
### 1. Docker跨平台注意事项
**Windows + Docker + Linux容器组合会暴露文件格式问题**
- Windows默认CRLF (`\r\n`)
- Linux默认LF (`\n`)
- Git的`autocrlf`设置可能自动转换
- 使用`.gitattributes`显式控制换行符
### 2. PHP配置文件最佳实践
```php
<?php
// 配置代码...
// ❌ 错误:有结束标签和空行
?>
```
```php
<?php
// 配置代码...
// ✅ 正确:没有结束标签
```
### 3. REDCap部署检查清单
- [ ] Apache DocumentRoot与Base URL一致
- [ ] 禁用压缩模块(开发环境)
- [ ] `database.php`末尾无`?>`
- [ ] 文件换行符统一为LF
- [ ] 密码哈希正确生成
- [ ] Session目录权限正确
---
## 🚀 后续部署到生产环境
**本地Docker开发环境已验证通过可以安全迁移到阿里云ECS**
1. ✅ 使用相同的`Dockerfile.redcap`构建镜像
2. ✅ 修改`database.php`连接到RDS
3. ✅ 生产环境可以启用Gzip压缩使用Nginx反向代理
4. ✅ 所有配置文件已经过验证不会有CRLF问题
**未来不需要逐个排查REDCap文件因为官方代码是规范的** ✨
---
## 📞 联系方式
如有问题,请查看:
- REDCap官方文档https://projectredcap.org/
- 部署方案文档:`docs/03-REDCap本地Docker开发环境部署方案.md`

View File

@@ -0,0 +1,61 @@
# REDCap Docker环境变量配置模板
# 版本v1.0
# 日期2026-01-01
# 用途:环境变量模板
# 使用方法:复制此文件为.env后修改
# Windows: copy env.template .env
# Linux/Mac: cp env.template .env
# ========== MySQL数据库配置开发环境 ==========
# ⚠️ 警告:这些是开发环境密码,生产环境必须修改!
# MySQL Root密码
MYSQL_ROOT_PASSWORD=redcap_root_dev_2026
# MySQL数据库名
MYSQL_DATABASE=redcap
# MySQL用户名
MYSQL_USER=redcap_user
# MySQL用户密码
MYSQL_PASSWORD=redcap_pass_dev_456
# ========== 生产环境配置ECS + RDS ==========
# 生产环境使用时,取消注释并修改以下配置:
# RDS MySQL连接信息
# REDCAP_DB_HOST=rm-xxxxxx.mysql.rds.aliyuncs.com
# REDCAP_DB_PORT=3306
# MYSQL_DATABASE=redcap_prod
# MYSQL_USER=redcap_user_prod
# MYSQL_PASSWORD=YOUR_STRONG_PASSWORD_HERE
# ========== REDCap Salt值 ==========
# ⚠️ 重要Salt一旦设置永远不可更改
# 用于数据去标识化哈希
# 开发环境Salt固定值便于重建环境
REDCAP_SALT=iit_dev_salt_2026_redcap_v15_do_not_change
# 生产环境Salt必须使用强随机值
# REDCAP_SALT=YOUR_STRONG_RANDOM_SALT_32_CHARS_MINIMUM_WITH_SPECIAL_CHARS
# ========== 时区配置 ==========
TZ=Asia/Shanghai
# ========== 开发工具配置 ==========
# phpMyAdmin仅开发环境
PMA_UPLOAD_LIMIT=50M
# ========== 注意事项 ==========
# 1. 复制此文件为.env后使用copy env.template .env
# 2. 不要将.env文件提交到Git已添加到.gitignore
# 3. 生产环境必须修改所有密码和Salt值
# 4. Salt值设置后永远不可更改
# 5. 生产环境密码建议使用32+字符的强密码
# 6. 可以使用以下命令生成随机密码:
# PowerShell: -join ((65..90) + (97..122) + (48..57) + (33..47) | Get-Random -Count 32 | % {[char]$_})
# Linux/Mac: openssl rand -base64 32

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
}