Features - User Management (Phase 4.1): - Database: Add user_modules table for fine-grained module permissions - Database: Add 4 user permissions (view/create/edit/delete) to role_permissions - Backend: UserService (780 lines) - CRUD with tenant isolation - Backend: UserController + UserRoutes (648 lines) - 13 API endpoints - Backend: Batch import users from Excel - Frontend: UserListPage (412 lines) - list/filter/search/pagination - Frontend: UserFormPage (341 lines) - create/edit with module config - Frontend: UserDetailPage (393 lines) - details/tenant/module management - Frontend: 3 modal components (592 lines) - import/assign/configure - API: GET/POST/PUT/DELETE /api/admin/users/* endpoints Architecture Upgrade - Module Permission System: - Backend: Add getUserModules() method in auth.service - Backend: Login API returns modules array in user object - Frontend: AuthContext adds hasModule() method - Frontend: Navigation filters modules based on user.modules - Frontend: RouteGuard checks requiredModule instead of requiredVersion - Frontend: Remove deprecated version-based permission system - UX: Only show accessible modules in navigation (clean UI) - UX: Smart redirect after login (avoid 403 for regular users) Fixes: - Fix UTF-8 encoding corruption in ~100 docs files - Fix pageSize type conversion in userService (String to Number) - Fix authUser undefined error in TopNavigation - Fix login redirect logic with role-based access check - Update Git commit guidelines v1.2 with UTF-8 safety rules Database Changes: - CREATE TABLE user_modules (user_id, tenant_id, module_code, is_enabled) - ADD UNIQUE CONSTRAINT (user_id, tenant_id, module_code) - INSERT 4 permissions + role assignments - UPDATE PUBLIC tenant with 8 module subscriptions Technical: - Backend: 5 new files (~2400 lines) - Frontend: 10 new files (~2500 lines) - Docs: 1 development record + 2 status updates + 1 guideline update - Total: ~4900 lines of code Status: User management 100% complete, module permission system operational
547 lines
37 KiB
Markdown
547 lines
37 KiB
Markdown
# **REDCap二次开发深度研究报告:架构体系、移动端交互与最佳实践全景解析**
|
||
|
||
## **1\. 执行摘要与架构背景**
|
||
|
||
Research Electronic Data Capture (REDCap) 已经从一个单一的数据收集工具演变为一个能够支持复杂临床试验、运营工作流和纵向研究的强大生态系统。虽然范德堡大学(Vanderbilt University)开发的核心应用程序提供了一套完善的调查管理和数据录入工具,但对于企业级研究和复杂临床数据管理而言,REDCap真正的潜力在于其“二次开发”能力。这一术语涵盖了通过外部模块(External Module, EM)框架、应用程序编程接口(API)、数据录入触发器(DET)以及涉及REDCap移动应用程序和MyCap的移动集成策略对REDCap进行的程序化扩展1。
|
||
|
||
本报告旨在提供关于REDCap二次开发的详尽技术分析。它不仅探讨了架构先决条件、从旧版插件(Plugin)向现代外部模块框架的过渡、安全编码实践,还深入剖析了移动端同步的复杂机制。此外,报告详细列出了特定的源代码模式,分析了常见的陷阱(即开发中的“坑”),并提供了在定制功能时维护系统完整性的最佳实践。
|
||
|
||
### **1.1 联盟模式与源码访问权限的特殊性**
|
||
|
||
与传统的开源软件不同,REDCap在一种独特的管理模式下运行。它对非营利组织免费提供,但并非公共领域的开源软件。为了获得二次开发所需的源代码,组织必须通过与范德堡大学签署最终用户许可协议(EULA)加入REDCap联盟3。
|
||
|
||
这种区别对开发者至关重要。源代码无法在GitHub等公共存储库中以可运行的格式获取;严格来说,核心代码库是联盟的专有财产。然而,扩展机制——特别是外部模块框架——是公开文档化的,且社区通过REDCap Repo分享了数百个模块1。为了进行深度的二次开发,开发者通常需要其所在机构的REDCap管理员授予本地服务器访问权限,以便检查核心PHP文件和进行调试6。
|
||
|
||
### **1.2 技术架构:LAMP栈与EAV模型**
|
||
|
||
二次开发要求对REDCap的底层基础设施有深刻的理解。REDCap构建在LAMP栈之上:
|
||
|
||
* **Linux/Windows:** 托管应用程序的操作系统。
|
||
* **Apache/IIS/Nginx:** 处理HTTP请求的Web服务器。
|
||
* **MySQL/MariaDB:** 关系型数据库管理系统。
|
||
* **PHP:** 用于核心逻辑和扩展的服务器端脚本语言。
|
||
|
||
REDCap被描述为“轻量级”,通常需要Web服务器和独立的数据库服务器。对于标准使用,Web服务器和数据库各分配10GB的存储空间通常足以支持第一年的高强度使用7。然而,二次开发往往会带来更高的资源需求。执行复杂查询或通过API处理大数据的自定义模块如果未经过优化,可能会给数据库带来巨大压力。
|
||
|
||
数据库模式主要采用实体-属性-值(Entity-Attribute-Value, EAV)模型,特别是redcap\_data表,它以狭窄的纵向格式(record\_id, project\_id, field\_name, value)存储绝大部分项目数据。这一架构决策允许在不更改数据库模式的情况下流畅地创建元数据驱动的表单,但这显著增加了二次开发中直接SQL查询的复杂性2。开发者必须小心地浏览此模式以避免性能下降。
|
||
|
||
## ---
|
||
|
||
**2\. 外部模块框架(External Module Framework):定制化的现代标准**
|
||
|
||
历史上,REDCap的定制是通过“Hooks(钩子)”和“Plugins(插件)”实现的——即直接注入Web服务器文件路径的脚本。虽然这种方法有效,但它非常脆弱;REDCap核心的升级经常导致定制功能失效,且跨多个项目管理版本在行政上是繁琐的9。
|
||
|
||
**外部模块(External Module, EM)框架**的引入彻底改变了二次开发的格局。它将自定义代码封装在带版本的包中,可以全局启用或按项目启用,并通过图形用户界面(GUI)进行管理,且能在联盟内共享1。
|
||
|
||
### **2.1 外部模块的解剖学结构**
|
||
|
||
一个外部模块是位于\<redcap-root\>/modules/目录下的文件集合。其命名约定非常严格:\<prefix\>\_v\<version\_number\>。例如,一个由前缀为“company”的开发者开发的名为“Hello World”的模块可能位于modules/company\_hello\_world\_v1.0.010。
|
||
|
||
外部模块的核心组件如下表所示:
|
||
|
||
| 组件名称 | 文件名 | 功能描述 |
|
||
| :---- | :---- | :---- |
|
||
| **配置清单** | config.json | 定义元数据、权限、链接、系统/项目设置以及Cron作业。它是模块的入口点。 |
|
||
| **逻辑类** | Module.php | 继承自AbstractExternalModule的PHP类。包含业务逻辑和钩子实现。 |
|
||
| **文档** | README.md | 使用说明(对于提交到Repo至关重要)。 |
|
||
| **许可证** | LICENSE | 许可条款(通常为MIT或类似条款以便于联盟共享)。 |
|
||
| **辅助文件** | /pages, /js | 用于存放自定义页面、JavaScript或CSS资源的子目录。 |
|
||
|
||
#### **2.1.1 配置文件 (config.json) 的深度解析**
|
||
|
||
config.json文件不仅是配置,它是模块的声明书。它告诉REDCap该模块能做什么以及它需要什么权限。如果JSON文件配置错误,模块将无法加载。
|
||
|
||
**源代码示范:config.json结构**
|
||
|
||
JSON
|
||
|
||
{
|
||
"name": "Advanced Data Processor",
|
||
"description": "在保存时处理数据并与外部API集成。",
|
||
"permissions": \[
|
||
"redcap\_save\_record",
|
||
"redcap\_every\_page\_top"
|
||
\],
|
||
"links": {
|
||
"project": \[
|
||
{
|
||
"name": "数据处理仪表盘",
|
||
"icon": "fas fa-chart-line",
|
||
"url": "pages/dashboard.php"
|
||
}
|
||
\],
|
||
"control-center": \[
|
||
{
|
||
"name": "处理器日志",
|
||
"icon": "fas fa-server",
|
||
"url": "pages/admin\_logs.php"
|
||
}
|
||
\]
|
||
},
|
||
"project-settings":,
|
||
"authors":
|
||
}
|
||
|
||
*案例分析:* permissions数组显式请求对特定钩子的访问权限。如果此处未列出某个钩子,即使在PHP类中定义了该函数,它也永远不会执行。project-settings数组在项目设置页面中创建了一个GUI,允许用户在不接触代码的情况下配置模块11。
|
||
|
||
#### **2.1.2 模块类 (ExternalModule.php) 的实现逻辑**
|
||
|
||
这个文件包含扩展AbstractExternalModule的PHP类。这种继承提供了对框架辅助方法的访问,如getProjectSetting、query和日志记录功能。
|
||
|
||
**源代码示范:类结构与逻辑封装**
|
||
|
||
PHP
|
||
|
||
\<?php
|
||
namespace Institution\\AdvancedDataProcessor;
|
||
|
||
use ExternalModules\\AbstractExternalModule;
|
||
use REDCap;
|
||
|
||
class AdvancedDataProcessor extends AbstractExternalModule {
|
||
|
||
// 当记录保存时自动触发的方法
|
||
public function redcap\_save\_record($project\_id, $record, $instrument, $event\_id, $group\_id, $survey\_hash, $response\_id, $repeat\_instance) {
|
||
|
||
// 1\. 检查该项目是否启用了模块逻辑
|
||
if ($this\-\>getProjectSetting('enable\_processing')\!== true) {
|
||
return;
|
||
}
|
||
|
||
// 2\. 防止无限循环!(Infinite Loop Trap)
|
||
// 如果此函数保存数据,它可能会再次触发redcap\_save\_record。
|
||
// 使用静态标志或检查保存是否由本模块触发是必须的。
|
||
static $is\_processing \= false;
|
||
if ($is\_processing) return;
|
||
$is\_processing \= true;
|
||
|
||
try {
|
||
// 3\. 执行核心逻辑
|
||
$this\-\>processData($project\_id, $record, $instrument);
|
||
} catch (\\Exception $e) {
|
||
$this\-\>emError("处理记录 $record 时出错: ". $e\-\>getMessage());
|
||
}
|
||
|
||
$is\_processing \= false;
|
||
}
|
||
|
||
private function processData($pid, $record, $form) {
|
||
// 实现细节
|
||
$endpoint \= $this\-\>getProjectSetting('api\_endpoint');
|
||
//... API 调用逻辑...
|
||
}
|
||
}
|
||
|
||
这种结构确保了封装性。通过使用namespace,模块避免了与其他可能使用相似类名的模块发生冲突13。
|
||
|
||
### **2.2 关键钩子(Hooks)与事件处理机制**
|
||
|
||
钩子是干预REDCap工作流的主要机制。它们允许开发者在应用程序生命周期的特定点执行代码9。
|
||
|
||
#### **2.2.1 redcap\_save\_record:核心数据处理**
|
||
|
||
这是二次开发中最重要的钩子。它在数据已提交到数据库*之后*,但在用户看到确认消息之前(在某些上下文中)或在后台保存后立即触发。
|
||
|
||
* **参数详解:** $project\_id(项目ID), $record(记录名), $instrument(表单名), $event\_id(事件ID), $group\_id(数据访问组ID), $survey\_hash(调查哈希), $response\_id(响应ID), $repeat\_instance(重复实例)14。
|
||
* **最佳应用场景:**
|
||
* **自动评分与计算:** 处理REDCap内置计算字段无法处理的复杂评分(例如,跨事件计算或涉及条件逻辑的聚合)。
|
||
* **数据录入触发器(DET)模拟:** 保存时立即将数据推送到外部注册表或电子病历系统(EMR)。
|
||
* **数据同步:** 自动将“筛选”项目中的数据复制到“主研究”项目中17。
|
||
* **致命陷阱(The Infinite Loop):** 一个常见的错误是redcap\_save\_record内部调用REDCap::saveData。由于saveData会再次触发redcap\_save\_record,这会导致无限递归,最终导致服务器崩溃(段错误或内存耗尽)。
|
||
* *解决方案:* 开发者必须包含逻辑来检查保存是否已在进行中,或使用标志在函数由模块本身触发时提前退出。
|
||
|
||
#### **2.2.2 redcap\_every\_page\_top:UI注入与全局控制**
|
||
|
||
此钩子在每个项目上下文的页面加载时执行。
|
||
|
||
* **最佳应用场景:**
|
||
* **UI/DOM操作:** 注入JavaScript(类似Shazam模块的方法)来修改DOM,基于复杂逻辑隐藏字段,或更改仪器的外观13。
|
||
* **CSS注入:** 加载自定义样式表以对项目进行品牌化。
|
||
* **性能警告:** 由于此钩子在*每一页*运行,在此钩子内进行繁重的数据库查询将严重降低用户体验。此处的代码必须极度轻量。
|
||
|
||
#### **2.2.3 redcap\_survey\_complete:参与者流程控制**
|
||
|
||
类似于save\_record,但专用于调查完成时。这是根据参与者的回答将他们重定向到不同URL,或发送超出标准“警报和通知”模块功能的自定义电子邮件通知的理想钩子18。
|
||
|
||
## ---
|
||
|
||
**3\. 数据库交互与安全工程**
|
||
|
||
二次开发中最大的风险之一是不当的数据库交互,这可能导致SQL注入(SQLi)漏洞。鉴于REDCap存储敏感的受保护健康信息(PHI),安全性至关重要。
|
||
|
||
### **3.1 抽象查询方法与SQL注入防御**
|
||
|
||
在旧版插件中,开发者经常使用db\_query("SELECT \* FROM table WHERE id \= $id")。**这是严重的安全违规**,因为如果$id是用户输入,它允许SQL注入19。
|
||
|
||
外部模块框架引入了安全的查询类。开发者应使用$this-\>query()(或ExternalModules::query),该方法支持参数化查询。
|
||
|
||
**脆弱代码(严禁使用):**
|
||
|
||
PHP
|
||
|
||
// 典型的SQL注入漏洞
|
||
$sql \= "SELECT value FROM redcap\_data WHERE project\_id \= ". $\_GET\['pid'\]. " AND field\_name \= '". $\_GET\['field'\]. "'";
|
||
$q \= db\_query($sql);
|
||
|
||
**安全代码(最佳实践):**
|
||
|
||
PHP
|
||
|
||
// 参数化查询
|
||
$sql \= "SELECT value FROM redcap\_data WHERE project\_id \=? AND field\_name \=?";
|
||
$q \= $this\-\>query($sql, \[$project\_id, $field\_name\]);
|
||
|
||
while ($row \= $q\-\>fetch\_assoc()) {
|
||
// 安全处理数据
|
||
}
|
||
|
||
使用?占位符确保数据库驱动程序对输入进行转义,从而中和攻击者注入的任何恶意SQL命令11。
|
||
|
||
### **3.2 跨站脚本攻击(XSS)的防御**
|
||
|
||
当模块向浏览器输出数据时——尤其是用户输入的数据——必须防止XSS。如果用户在文本字段中输入\<script\>alert('Hack');\</script\>,而模块在仪表板上显示该字段且未进行转义,脚本将在查看者的浏览器中执行。
|
||
|
||
最佳实践:
|
||
始终将输出包裹在REDCap::escapeHtml()中,或使用框架的强制方法。
|
||
|
||
PHP
|
||
|
||
echo "用户备注: ". REDCap::escapeHtml($user\_note);
|
||
|
||
未能执行此操作是模块在联盟审查过程中被拒绝的主要原因22。
|
||
|
||
### **3.3 数据访问组(DAGs)与权限隔离**
|
||
|
||
当直接针对redcap\_data编写SQL查询时,模块会绕过REDCap的应用程序级安全性,包括数据访问组(DAGs)。查询可能会无意中返回项目中的所有记录,从而允许站点A的用户看到站点B的数据。
|
||
|
||
最佳实践:
|
||
只要可能,请使用REDCap::getData()方法代替原始SQL。REDCap::getData()会自动尊重DAG和用户权限。
|
||
|
||
PHP
|
||
|
||
$data \= REDCap::getData($project\_id, 'array', $record\_id);
|
||
|
||
如果出于性能原因必须使用原始SQL,开发者*必须*手动连接redcap\_data\_access\_groups表,并根据当前用户的group\_id进行过滤24。
|
||
|
||
## ---
|
||
|
||
**4\. 移动端交互:REDCap Mobile App深度解析**
|
||
|
||
REDCap服务器与移动设备之间的交互是二次开发的关键领域,特别是在互联网连接较差的地区进行实地研究时。
|
||
|
||
### **4.1 REDCap Mobile App的架构与工作流**
|
||
|
||
REDCap Mobile App是一个“胖客户端”,它将项目结构(元数据)和数据(可选)下载到本地设备。它充当本地Web服务器,允许离线数据收集。当恢复连接时,它通过REDCap API将数据同步回中央服务器25。
|
||
|
||
### **4.2 API同步机制与JSON Payload**
|
||
|
||
同步过程高度依赖于API令牌(Token)。
|
||
|
||
1. **令牌生成:** 用户在服务器端生成令牌。
|
||
2. **初始化:** 应用程序扫描包含初始化代码的二维码,该代码验证设备并下载项目XML(元数据)25。
|
||
3. **数据传输:** 设备上收集的数据存储在加密的SQLCipher数据库中(iOS/Android)。同步时,App向importRecords API端点发送JSON有效负载。
|
||
|
||
JSON Payload结构(同步):
|
||
API期望数据采用特定的JSON结构。对于构建自己的移动接口(替代官方App)的二次开发者来说,遵守此模式是强制性的。
|
||
|
||
JSON
|
||
|
||
\[
|
||
{
|
||
"record\_id": "101",
|
||
"redcap\_event\_name": "baseline\_arm\_1",
|
||
"first\_name": "John",
|
||
"age": "30",
|
||
"demographics\_complete": "2"
|
||
}
|
||
\]
|
||
|
||
28。
|
||
|
||
### **4.3 冲突解决与风险管理**
|
||
|
||
移动集成中的一个主要“陷阱”是**同步冲突**。如果用户A在服务器上编辑记录101,而用户B在离线移动应用程序上编辑记录101,则同步期间会发生冲突。REDCap Mobile App具有基本的冲突解决界面,要求用户选择“服务器版本”或“设备版本”。
|
||
|
||
**二次开发启示:** 如果您正在构建自动脚本(例如DET)来修改正在被移动数据收集者使用的记录,则会增加冲突的风险。
|
||
|
||
* *最佳实践:* 移动用户应分配新的、唯一的记录或特定的DAG,以防止与服务器端进程发生重叠编辑30。
|
||
|
||
## ---
|
||
|
||
**5\. MyCap:参与者端的定制与交互**
|
||
|
||
虽然REDCap Mobile App是面向研究人员的,但**MyCap**是面向参与者的。MyCap最初是一个外部模块,后在13.0版本中被集成到REDCap核心中,突显了其重要性32。
|
||
|
||
### **5.1 架构:ResearchKit与ResearchStack**
|
||
|
||
MyCap利用了Apple的**ResearchKit**(iOS)和**ResearchStack**(Android)。这些是专为医学研究应用程序设计的开源框架。MyCap充当桥梁:
|
||
|
||
1. **配置:** 研究人员在REDCap中配置任务。
|
||
2. **转换:** MyCap将REDCap元数据转换为ResearchKit对象定义。
|
||
3. **执行:** 应用程序将这些对象渲染为原生移动视图(而非Web视图),提供流畅的App体验34。
|
||
|
||
### **5.2 主动任务(Active Tasks)的定制**
|
||
|
||
MyCap最独特的功能是“主动任务”——利用手机传感器(加速度计、麦克风、陀螺仪)测量认知或身体功能的活动(例如,敲击速度、步态与平衡、空间记忆)37。
|
||
|
||
二次开发机会:
|
||
开发者可以创建自定义的主动任务,但这需要Swift(iOS)或Kotlin/Java(Android)的高级知识,并修改MyCap源代码(这需要不同于REDCap核心许可的特定联盟App源代码许可)。然而,标准的二次开发通常侧重于触发MyCap操作或处理MyCap数据。
|
||
|
||
* *案例:* 一个外部模块,通过redcap\_save\_record监控传入的MyCap主动任务数据,如果参与者的“步态速度”低于特定阈值(表明跌倒风险),则触发警报38。
|
||
|
||
### **5.3 通过外部模块定制MyCap**
|
||
|
||
尽管MyCap是核心功能,EM仍然可以增强它。例如,生成用于参与者入职的自定义二维码并自动通过电子邮件发送。App Links功能允许从外部源深度链接到MyCap应用程序39。
|
||
|
||
## ---
|
||
|
||
**6\. REDCap API:生态系统的自动化桥梁**
|
||
|
||
API是互操作性的支柱。对于二次开发而言,它通常是编写外部模块的替代方案。如果逻辑可以通过在Cron作业上运行的外部脚本(Python/R)来处理,那么这通常比在服务器上安装PHP模块更安全。
|
||
|
||
### **6.1 导出与导入的最佳实践**
|
||
|
||
* **分批处理(Batching):** 导出大型数据集时,一次请求所有记录会导致超时。
|
||
* *解决方案:* 使用batch\_size参数或分块循环遍历记录。
|
||
* **类型处理:** 默认情况下,API在JSON中将所有数据作为字符串返回。
|
||
* *陷阱:* 在PHP/Python布尔检查中,字段值“0”(字符串)在某些上下文中为真,但“0”(整数)为假。开发者必须严格对API响应进行类型转换40。
|
||
* **“扁平”与“EAV”导出:** API创建一个“扁平”文件(每个记录/事件一行)。这与后端的EAV结构不同。二次开发者通常构建“数据录入触发器”(DET),每当保存记录时,该触发器都会收到来自REDCap的POST请求,然后调用API导出该特定记录进行处理42。
|
||
|
||
**代码示范:Python API导出脚本**
|
||
|
||
Python
|
||
|
||
import requests
|
||
import pandas as pd
|
||
|
||
api\_url \= 'https://redcap.institution.edu/api/'
|
||
\# payload构造
|
||
payload \= {
|
||
'token': 'YOUR\_32\_CHAR\_TOKEN',
|
||
'content': 'record',
|
||
'format': 'json',
|
||
'type': 'flat',
|
||
\# 仅获取特定记录以节省带宽
|
||
'records': '101'
|
||
}
|
||
|
||
try:
|
||
response \= requests.post(api\_url, data=payload)
|
||
response.raise\_for\_status() \# 检查HTTP错误
|
||
data \= response.json()
|
||
|
||
\# 转换为DataFrame进行处理
|
||
df \= pd.DataFrame(data)
|
||
print(df.head())
|
||
|
||
except requests.exceptions.RequestException as e:
|
||
print(f"API请求失败: {e}")
|
||
except ValueError:
|
||
print("JSON解码失败 \- 响应可能非JSON格式")
|
||
|
||
44。
|
||
|
||
## ---
|
||
|
||
**7\. 最佳案例研究(Case Studies)**
|
||
|
||
为了说明“最佳应用”,我们分析三种突出的二次开发方法。
|
||
|
||
### **7.1 案例一:Shazam(UI与前端改造)**
|
||
|
||
* **目标:** 为调查创建自定义布局,将字段分组为矩阵或非标准视觉格式。
|
||
* **机制:** Shazam是一个外部模块,它注入JavaScript/CSS。它解析描述性文本字段中的特定“Shazam”标签,然后重新排列数据录入表单的HTML DOM。
|
||
* **洞察:** 这展示了EM如何在不更改服务器端数据结构的情况下,从*客户端*彻底改变用户体验1。
|
||
|
||
### **7.2 案例二:Auto-Schedule(工作流自动化)**
|
||
|
||
* **目标:** 基于基线日期(例如手术日期)自动生成纵向事件的时间表。
|
||
* **机制:** 使用redcap\_save\_record钩子。当保存“surgery\_date”字段时,模块计算未来日期(+30天,+60天)并填充项目日历。
|
||
* **洞察:** 这替代了人工计算,减少了协调员的错误,展示了后端钩子在运营效率中的作用45。
|
||
|
||
### **7.3 案例三:Cross-Project Piping(跨项目数据互通)**
|
||
|
||
* **目标:** 将人口统计数据从中央“注册”项目拉取到特定的“研究”项目中。
|
||
* **机制:** 一个EM,它查询源项目的数据库(使用REDCap::getData)并将数据插入当前项目表单。
|
||
* **成功关键:** 它使用“触发字段”。只有在修改特定字段时才会进行复制,防止不断覆盖47。
|
||
|
||
## ---
|
||
|
||
**8\. 避坑指南:常见问题与解决方案**
|
||
|
||
二次开发充满风险。以下是联盟中报告的最常见问题:
|
||
|
||
### **8.1 “升级致死”(The Upgrade Death)**
|
||
|
||
* **场景:** 开发者使用非标准文件路径编写插件,或依赖于REDCap内部(私有)核心函数。
|
||
* **后果:** 当REDCap更新时,函数名称更改或路径移动,导致插件崩溃。
|
||
* **避坑指南:** 严格坚持使用外部模块框架,并仅调用REDCap::类方法,这些方法为了向后兼容性而受到维护。
|
||
|
||
### **8.2 redcap\_data的性能瓶颈**
|
||
|
||
* **场景:** 模块搜索“所有年龄 \> 50的记录”。
|
||
* **陷阱:** 在一个拥有10万条记录的项目中,通过SELECT \* FROM redcap\_data WHERE value \> 50执行此操作会强制对表进行全表扫描(因为该表包含*所有*项目的数据)。
|
||
* **解决方案:** 始终在SQL查询中包含project\_id作为首要过滤条件。利用REDCap::getData()的过滤逻辑,或者如果需要原始SQL,确保有效地利用了project\_id和field\_name上的索引。
|
||
|
||
### **8.3 调查页面死循环(Survey Loop)**
|
||
|
||
* **场景:** 使用redcap\_survey\_page\_top钩子在满足条件时重定向用户。
|
||
* **陷阱:** 如果重定向逻辑有缺陷(例如,重定向条件在目标页面上也为真),用户将被弹回同一页面,导致浏览器挂起或崩溃。
|
||
* **解决方案:** 在执行重定向之前,检查当前URL是否已经是目标URL。
|
||
|
||
### **8.4 移动同步中的“孤儿数据”**
|
||
|
||
* **场景:** 当移动设备检出项目时,管理员更改了项目结构(例如,删除了一个字段)。
|
||
* **后果:** 移动用户无法将数据同步回来,因为服务器上不再存在该字段。数据被困在设备上。
|
||
* **规则:** **绝对不要**在项目处于“生产”状态且有活跃移动用户时修改项目设计30。
|
||
|
||
## ---
|
||
|
||
**9\. 结论**
|
||
|
||
REDCap的二次开发将一个被动的数据存储库转变为一个主动的研究操作系统。从临时插件向结构化外部模块框架的迁移代表了生态系统的成熟,优先考虑了安全性、可维护性和共享能力。
|
||
|
||
对于开发者而言,成功的路径在于严格遵守框架规则:使用抽象查询方法防止SQL注入,清理输出以防止XSS,并利用带有无限循环保护的标准钩子如redcap\_save\_record。
|
||
|
||
在移动领域,MyCap和Mobile App的集成将REDCap的触角延伸到了患者的口袋和偏远的实地现场。然而,这种连接性要求在API令牌管理和项目版本控制方面有严格的操作纪律,以防止数据丢失。
|
||
|
||
通过利用这些高级功能——同时尊重联盟源代码的架构边界——机构可以部署既安全又可扩展的复杂、自动化和用户友好的研究环境。
|
||
|
||
## ---
|
||
|
||
**10\. 技术附录:核心源代码参考库**
|
||
|
||
### **A.1 基础 redcap\_save\_record 实现模板**
|
||
|
||
PHP
|
||
|
||
public function redcap\_save\_record($project\_id, $record, $instrument, $event\_id, $group\_id, $survey\_hash, $response\_id, $repeat\_instance)
|
||
{
|
||
// 确保我们在正确的项目上下文中
|
||
if ($project\_id\!= $this\-\>getProjectSetting('target\_project')) return;
|
||
|
||
// 加载数据以检查条件
|
||
$data \= \\REDCap::getData($project\_id, 'array', $record);
|
||
|
||
// 检查'status'字段是否为'complete' (2)
|
||
// 注意:事件结构处理
|
||
if ($data\[$record\]\[$event\_id\]\['status'\] \== '2') {
|
||
// 记录日志
|
||
$this\-\>log("记录 $record 完成状态检查。", \[
|
||
'record' \=\> $record,
|
||
'status' \=\> 'complete'
|
||
\]);
|
||
|
||
// 执行自定义逻辑(例如,调用外部API)
|
||
$this\-\>sendToExternalRegistry($record, $data);
|
||
}
|
||
}
|
||
|
||
### **A.2 安全数据库查询(参数化)**
|
||
|
||
PHP
|
||
|
||
// 错误的写法(SQL注入风险)
|
||
// $sql \= "select value from redcap\_data where record \= '$record\_id'";
|
||
|
||
// 正确的写法
|
||
$sql \= "select value from redcap\_data where project\_id \=? and record \=? and field\_name \=?";
|
||
$result \= $this\-\>query($sql, \[$project\_id, $record\_id, 'target\_field'\]);
|
||
|
||
while($row \= $result\-\>fetch\_assoc()){
|
||
// 安全使用 $row\['value'\]
|
||
$value \= $row\['value'\];
|
||
//...处理逻辑
|
||
}
|
||
|
||
### **A.3 API Python 交互(处理大批量数据)**
|
||
|
||
Python
|
||
|
||
def export\_large\_project(api\_url, token):
|
||
"""
|
||
分批导出大型项目数据以避免超时
|
||
"""
|
||
\# 1\. 首先获取所有记录ID
|
||
payload \= {
|
||
'token': token,
|
||
'content': 'record',
|
||
'format': 'json',
|
||
'fields': 'record\_id'
|
||
}
|
||
r \= requests.post(api\_url, data=payload)
|
||
records \= \[x\['record\_id'\] for x in r.json()\]
|
||
|
||
\# 2\. 分块处理 (例如每块100条)
|
||
chunk\_size \= 100
|
||
all\_data \=
|
||
|
||
for i in range(0, len(records), chunk\_size):
|
||
chunk \= records\[i:i \+ chunk\_size\]
|
||
\# 构建请求特定的记录
|
||
batch\_payload \= {
|
||
'token': token,
|
||
'content': 'record',
|
||
'format': 'json',
|
||
'type': 'flat'
|
||
}
|
||
\# 动态添加记录ID到payload
|
||
for idx, rec\_id in enumerate(chunk):
|
||
batch\_payload\[f'records\[{idx}\]'\] \= rec\_id
|
||
|
||
r\_batch \= requests.post(api\_url, data=batch\_payload)
|
||
all\_data.extend(r\_batch.json())
|
||
print(f"已导出 {len(all\_data)} 条记录...")
|
||
|
||
return pd.DataFrame(all\_data)
|
||
|
||
#### **引用的著作**
|
||
|
||
1. Supporting rapid innovation in research data capture and management: the REDCap external module framework \- PubMed Central, 访问时间为 十二月 29, 2025, [https://pmc.ncbi.nlm.nih.gov/articles/PMC12202089/](https://pmc.ncbi.nlm.nih.gov/articles/PMC12202089/)
|
||
2. The Process of Installing REDCap, a Web Based Database Supporting Biomedical Research: The First Year \- PubMed Central, 访问时间为 十二月 29, 2025, [https://pmc.ncbi.nlm.nih.gov/articles/PMC4287671/](https://pmc.ncbi.nlm.nih.gov/articles/PMC4287671/)
|
||
3. Join & Get REDCap, 访问时间为 十二月 29, 2025, [https://projectredcap.org/join/](https://projectredcap.org/join/)
|
||
4. How to Acquire a REDCap License \- NACC Docs, 访问时间为 十二月 29, 2025, [https://docs.naccdata.org/edc/data-capture-development/how-to-acquire-a-redcap-license](https://docs.naccdata.org/edc/data-capture-development/how-to-acquire-a-redcap-license)
|
||
5. 访问时间为 十二月 29, 2025, [https://projectredcap.org/join/\#:\~:text=Although%20REDCap%20is%20available%20at,your%20organization%20must%20be%20executed.](https://projectredcap.org/join/#:~:text=Although%20REDCap%20is%20available%20at,your%20organization%20must%20be%20executed.)
|
||
6. FAQ \- REDCap, 访问时间为 十二月 29, 2025, [https://projectredcap.org/about/faq/](https://projectredcap.org/about/faq/)
|
||
7. Installation & Technical Requirements \- REDCap, 访问时间为 十二月 29, 2025, [https://projectredcap.org/software/requirements/](https://projectredcap.org/software/requirements/)
|
||
8. REDCap Technical Overview Introduction REDCap Infrastructure: Best Practices and Dependencies, 访问时间为 十二月 29, 2025, [https://projectredcap.org/wp-content/resources/REDCapTechnicalOverview.pdf](https://projectredcap.org/wp-content/resources/REDCapTechnicalOverview.pdf)
|
||
9. REDCap External Module Development for REDCap Admins and Developers, 访问时间为 十二月 29, 2025, [https://ctsit.github.io/redcap\_external\_module\_development\_guide/guide\_for\_admins\_and\_devs.html](https://ctsit.github.io/redcap_external_module_development_guide/guide_for_admins_and_devs.html)
|
||
10. REDCap 'Hello World' external module development guide \- Ayesh Alshukri, 访问时间为 十二月 29, 2025, [https://ayeshalshukri.co.uk/category/guides/redcap-external-module-development-guide-hello-world/](https://ayeshalshukri.co.uk/category/guides/redcap-external-module-development-guide-hello-world/)
|
||
11. REDCap External Module Development for Developers \- GitHub Pages, 访问时间为 十二月 29, 2025, [https://ctsit.github.io/redcap\_external\_module\_development\_guide/guide\_for\_devs.html](https://ctsit.github.io/redcap_external_module_development_guide/guide_for_devs.html)
|
||
12. REDCap External Module Development Beginner's Guide \- GitHub, 访问时间为 十二月 29, 2025, [https://github.com/vanderbilt-redcap/external-module-framework-docs/blob/main/guide.md](https://github.com/vanderbilt-redcap/external-module-framework-docs/blob/main/guide.md)
|
||
13. Shazam.php \- GitHub, 访问时间为 十二月 29, 2025, [https://github.com/susom/redcap-em-shazam/blob/master/Shazam.php](https://github.com/susom/redcap-em-shazam/blob/master/Shazam.php)
|
||
14. redcap-copy-data-on-save/CopyDataOnSave.php at main · lsgs ..., 访问时间为 十二月 29, 2025, [https://github.com/lsgs/redcap-copy-data-on-save/blob/main/CopyDataOnSave.php](https://github.com/lsgs/redcap-copy-data-on-save/blob/main/CopyDataOnSave.php)
|
||
15. README.md · main · BRIC / Epic Hl7 Integration · GitLab, 访问时间为 十二月 29, 2025, [https://gitlab.msu.edu/bric/epic-hl7-integration/-/blob/main/README.md](https://gitlab.msu.edu/bric/epic-hl7-integration/-/blob/main/README.md)
|
||
16. REDCap-Changelog\_8.1.0.docx, 访问时间为 十二月 29, 2025, [https://www.bu.edu/ctsi/files/2016/02/REDCap-Changelog\_8.1.0.docx](https://www.bu.edu/ctsi/files/2016/02/REDCap-Changelog_8.1.0.docx)
|
||
17. vanderbilt-redcap/auto-record-generation: Module that allows for a new record to be generated in another project (or the same project) on a flagging field being saved. Allows for data fields to be transferred to the new record as well. \- GitHub, 访问时间为 十二月 29, 2025, [https://github.com/vanderbilt-redcap/auto-record-generation](https://github.com/vanderbilt-redcap/auto-record-generation)
|
||
18. 2018 REDCapCon Poster Competition, 访问时间为 十二月 29, 2025, [https://projectredcap.org/wp-content/uploads/2018/08/2018-REDCapCon-Posters.pdf](https://projectredcap.org/wp-content/uploads/2018/08/2018-REDCapCon-Posters.pdf)
|
||
19. vanderbilt-redcap/external-module-framework-docs \- GitHub, 访问时间为 十二月 29, 2025, [https://github.com/vanderbilt-redcap/external-module-framework-docs](https://github.com/vanderbilt-redcap/external-module-framework-docs)
|
||
20. CVE-2017-7351: REDCap 7.0.0 \- 7.0.10 SQL Injection \- LRQA, 访问时间为 十二月 29, 2025, [https://www.lrqa.com/en/cyber-labs/cve-2017-7351-redcap-7-0-0-7-0-10-sql-injection/](https://www.lrqa.com/en/cyber-labs/cve-2017-7351-redcap-7-0-0-7-0-10-sql-injection/)
|
||
21. ctsit/redcap\_webservices: REDCap external module that provides a way to expose SQL query results to the external world. \- GitHub, 访问时间为 十二月 29, 2025, [https://github.com/ctsit/redcap\_webservices](https://github.com/ctsit/redcap_webservices)
|
||
22. REDCap: Multiple Cross-Site Scripting (XSS) Vulnerabilities \- LevelBlue, 访问时间为 十二月 29, 2025, [https://levelblue.com/blogs/spiderlabs-blog/redcap-multiple-cross-site-scripting-xss-vulnerabilities](https://levelblue.com/blogs/spiderlabs-blog/redcap-multiple-cross-site-scripting-xss-vulnerabilities)
|
||
23. Yale External Module (EM): Checklist for EM Development \- REDCap@Yale, 访问时间为 十二月 29, 2025, [https://portal.redcap.yale.edu/media/91/download?inline](https://portal.redcap.yale.edu/media/91/download?inline)
|
||
24. Article \- REDCap Security Information \- TeamDynamix, 访问时间为 十二月 29, 2025, [https://ecu.teamdynamix.com/TDClient/1409/Portal/KB/ArticleDet?ID=67288](https://ecu.teamdynamix.com/TDClient/1409/Portal/KB/ArticleDet?ID=67288)
|
||
25. Mobile App Guide \- CENTER FOR RESEARCH INFORMATICS, 访问时间为 十二月 29, 2025, [https://cri.uchicago.edu/wp-content/uploads/2015/12/REDCap-Mobile-App-Guide.pdf](https://cri.uchicago.edu/wp-content/uploads/2015/12/REDCap-Mobile-App-Guide.pdf)
|
||
26. Mobile App User's Guide, 访问时间为 十二月 29, 2025, [https://www.ctsi.ufl.edu/wordpress/files/2023/12/new-REDCap-Mobile-App-Guide-1.pdf](https://www.ctsi.ufl.edu/wordpress/files/2023/12/new-REDCap-Mobile-App-Guide-1.pdf)
|
||
27. CFRI DM REDCap Mobile App Manual, 访问时间为 十二月 29, 2025, [https://projectredcap.org/wp-content/uploads/2016/08/CFRI-DM-REDCap-Mobile-App-Manual.pdf](https://projectredcap.org/wp-content/uploads/2016/08/CFRI-DM-REDCap-Mobile-App-Manual.pdf)
|
||
28. Records \- PyCap \- REDCap-Tools, 访问时间为 十二月 29, 2025, [http://redcap-tools.github.io/PyCap/api\_reference/records/](http://redcap-tools.github.io/PyCap/api_reference/records/)
|
||
29. API-Best-Practices-and-Guide-1.docx \- UConn Health, 访问时间为 十二月 29, 2025, [https://health.uconn.edu/clinical-research-center/wp-content/uploads/sites/50/2024/02/API-Best-Practices-and-Guide-1.docx](https://health.uconn.edu/clinical-research-center/wp-content/uploads/sites/50/2024/02/API-Best-Practices-and-Guide-1.docx)
|
||
30. REDCap: Updating Mobile App Projects \- SMPH Enterprise Applications \- Research KB, 访问时间为 十二月 29, 2025, [https://kb.wisc.edu/smph/informatics/page.php?id=152765](https://kb.wisc.edu/smph/informatics/page.php?id=152765)
|
||
31. In-Depth Guide | REDCap, 访问时间为 十二月 29, 2025, [https://projectredcap.org/wp-content/uploads/2019/07/In-Depth-Guide2019.pdf](https://projectredcap.org/wp-content/uploads/2019/07/In-Depth-Guide2019.pdf)
|
||
32. Services | REDCap \- The George Washington University, 访问时间为 十二月 29, 2025, [https://redcap.smhs.gwu.edu/services](https://redcap.smhs.gwu.edu/services)
|
||
33. MyCap Resources, 访问时间为 十二月 29, 2025, [https://projectmycap.org/mycap-resources/](https://projectmycap.org/mycap-resources/)
|
||
34. MyCap – Mobilizing the participant voice, 访问时间为 十二月 29, 2025, [https://projectmycap.org/](https://projectmycap.org/)
|
||
35. MyCap: a flexible and configurable platform for mobilizing the participant voice \- PMC, 访问时间为 十二月 29, 2025, [https://pmc.ncbi.nlm.nih.gov/articles/PMC9165428/](https://pmc.ncbi.nlm.nih.gov/articles/PMC9165428/)
|
||
36. MyCap \- REDCap Support \- University of Alberta, 访问时间为 十二月 29, 2025, [https://help.redcap.ualberta.ca/help-and-faq/mycap](https://help.redcap.ualberta.ca/help-and-faq/mycap)
|
||
37. REDCap: MyCap \- Active Task List \- SMPH Enterprise Applications \- Research KB, 访问时间为 十二月 29, 2025, [https://kb.wisc.edu/smph/informatics/133154](https://kb.wisc.edu/smph/informatics/133154)
|
||
38. REDCap External Module – MyCap, 访问时间为 十二月 29, 2025, [https://projectmycap.org/tag/redcap-external-module/](https://projectmycap.org/tag/redcap-external-module/)
|
||
39. MYCAP HELP Table of Contents \- REDCap, 访问时间为 十二月 29, 2025, [https://redcap.med.upenn.edu/redcap\_v14.3.13/Resources/misc/mycap\_help.pdf](https://redcap.med.upenn.edu/redcap_v14.3.13/Resources/misc/mycap_help.pdf)
|
||
40. How to use exportRecordsTyped function from the redcapAPI package to import the data without factors? \- Stack Overflow, 访问时间为 十二月 29, 2025, [https://stackoverflow.com/questions/76815004/how-to-use-exportrecordstyped-function-from-the-redcapapi-package-to-import-the](https://stackoverflow.com/questions/76815004/how-to-use-exportrecordstyped-function-from-the-redcapapi-package-to-import-the)
|
||
41. JSONDecodeError · Issue \#265 · redcap-tools/PyCap \- GitHub, 访问时间为 十二月 29, 2025, [https://github.com/redcap-tools/PyCap/issues/265](https://github.com/redcap-tools/PyCap/issues/265)
|
||
42. Importing data into REDCap • Backup options • API Basics \- ITHS, 访问时间为 十二月 29, 2025, [https://www.iths.org/wp-content/uploads/REDCap-Importing-Exporting-302.pdf](https://www.iths.org/wp-content/uploads/REDCap-Importing-Exporting-302.pdf)
|
||
43. BCCHR-IT/data-entry-trigger-builder: An External Module that provides an interface to create a DET between a source and destination project. \- GitHub, 访问时间为 十二月 29, 2025, [https://github.com/BCCHR-IT/data-entry-trigger-builder](https://github.com/BCCHR-IT/data-entry-trigger-builder)
|
||
44. RedCap API export \- Python Discussions, 访问时间为 十二月 29, 2025, [https://discuss.python.org/t/redcap-api-export/32252](https://discuss.python.org/t/redcap-api-export/32252)
|
||
45. REDCap External Module for automated generation of record event schedules. \- GitHub, 访问时间为 十二月 29, 2025, [https://github.com/lsgs/redcap-autoschedule](https://github.com/lsgs/redcap-autoschedule)
|
||
46. redcap-autoschedule/README.md at master \- GitHub, 访问时间为 十二月 29, 2025, [https://github.com/lsgs/redcap-autoschedule/blob/master/README.md](https://github.com/lsgs/redcap-autoschedule/blob/master/README.md)
|
||
47. redcap-repo · GitHub Topics, 访问时间为 十二月 29, 2025, [https://github.com/topics/redcap-repo](https://github.com/topics/redcap-repo)
|
||
48. A Comprehensive Guide to REDCap | UNMC, 访问时间为 十二月 29, 2025, [https://www.unmc.edu/vcr/\_documents/unmc\_redcap\_usage.pdf](https://www.unmc.edu/vcr/_documents/unmc_redcap_usage.pdf) |